Auto merge of #147784 - nxsaken:div_exact_return_option, r=dtolnay
Return `Option` from `exact_div` and inherit overflow checks
According to https://github.com/rust-lang/rust/issues/139911#issuecomment-3404056127, `exact_div` should return `Option::None` if `self % rhs != 0`, panic if `rhs == 0`, and handle overflow conditionally (panic in debug, wrap in release).
rust-lang/rust#147771 should rename `exact_div` to `div_exact`.
diff --git a/Cargo.lock b/Cargo.lock
index 267b516..535833d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -235,6 +235,7 @@
version = "0.0.0"
dependencies = [
"arbitrary",
+ "cfg",
"expect-test",
"intern",
"oorandom",
@@ -258,28 +259,6 @@
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
-name = "chalk-derive"
-version = "0.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ea9b1e80910f66ae87c772247591432032ef3f6a67367ff17f8343db05beafa"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "chalk-ir"
-version = "0.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7047a516de16226cd17344d41a319d0ea1064bf9e60bd612ab341ab4a34bbfa8"
-dependencies = [
- "bitflags 2.9.4",
- "chalk-derive",
-]
-
-[[package]]
name = "clap"
version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -776,8 +755,6 @@
"arrayvec",
"base-db",
"bitflags 2.9.4",
- "chalk-derive",
- "chalk-ir",
"cov-mark",
"either",
"ena",
@@ -819,11 +796,11 @@
[[package]]
name = "home"
-version = "0.5.11"
+version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.61.0",
]
[[package]]
@@ -929,6 +906,7 @@
"ide-diagnostics",
"ide-ssr",
"itertools",
+ "macros",
"nohash-hasher",
"oorandom",
"profile",
@@ -975,6 +953,7 @@
"hir",
"ide-db",
"itertools",
+ "macros",
"smallvec",
"stdx",
"syntax",
@@ -999,6 +978,7 @@
"indexmap",
"itertools",
"line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "macros",
"memchr",
"nohash-hasher",
"parser",
@@ -1008,6 +988,7 @@
"rustc-hash 2.1.1",
"salsa",
"salsa-macros",
+ "smallvec",
"span",
"stdx",
"syntax",
@@ -1404,14 +1385,14 @@
[[package]]
name = "mio"
-version = "1.0.4"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
dependencies = [
"libc",
"log",
"wasi",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.0",
]
[[package]]
@@ -1467,11 +1448,11 @@
[[package]]
name = "nu-ansi-term"
-version = "0.50.1"
+version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1578,6 +1559,7 @@
"rustc-literal-escaper 0.0.4",
"stdx",
"tracing",
+ "winnow",
]
[[package]]
@@ -1842,9 +1824,9 @@
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c063a7fef3c49d03837ee9a5d988aad83630c3460b03b32355c279d3fafa7d07"
+checksum = "a4ce5c9ea794353e02beae390c4674f74ffb23a2ad9de763469fdcef5c1026ef"
dependencies = [
"bitflags 2.9.4",
"ra-ap-rustc_hashes",
@@ -1854,24 +1836,24 @@
[[package]]
name = "ra-ap-rustc_ast_ir"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a210dbd77e794b33ff17d2d15750dee44eeabd1330685d69a6bad272d515892a"
+checksum = "1696b77af9bbfe1fcc7a09c907561061c6ef4c8bd6d5f1675b927bc62d349103"
[[package]]
name = "ra-ap-rustc_hashes"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea031ea45bb92cd346ed222b35c812e355f304183096ee91bb437b3813c6348"
+checksum = "c055d8b0d8a592d8cf9547495189f52c1ee5c691d28df1628253a816214e8521"
dependencies = [
"rustc-stable-hash",
]
[[package]]
name = "ra-ap-rustc_index"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0114f842b20cba9beb2d9002ca31ae706b47f28ba2d6a49cbf9fd65fa72b9d"
+checksum = "a08a03e3d4a452144b68f48130eda3a2894d4d79e99ddb44bdb4e0ab8c384e10"
dependencies = [
"ra-ap-rustc_index_macros",
"smallvec",
@@ -1879,9 +1861,9 @@
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc738a5bb06fb3893725fbeb3640ff1822bb2aae3f416c4a49f0a706ba89d1cc"
+checksum = "a1e0446b4d65a8ce19d8fd12826c4bf2365ffa4b8fe0ee94daf5968fe36e920c"
dependencies = [
"proc-macro2",
"quote",
@@ -1890,9 +1872,9 @@
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c35b3d812cfc101d3f534640c13f24c0ec50ee2249685e4c20b2868609c9ee"
+checksum = "ac80365383a3c749f38af567fdcfaeff3fa6ea5df3846852abbce73e943921b9"
dependencies = [
"memchr",
"unicode-properties",
@@ -1901,9 +1883,9 @@
[[package]]
name = "ra-ap-rustc_next_trait_solver"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7b0fa6fb8e0717ebd0836f8de4a6efc954fca1a8652980fd2584dbe448c7d95"
+checksum = "a39b419d2d6f7fdec7e0981b7fb7d5beb5dda7140064f1199704ec9dadbb6f73"
dependencies = [
"derive-where",
"ra-ap-rustc_index",
@@ -1914,9 +1896,9 @@
[[package]]
name = "ra-ap-rustc_parse_format"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d01bad23470cc749ef607476890aabcc8993ca3ef87d4241d0f6a08c6f9402"
+checksum = "b743b0c8f795842e41b1720bbc5af6e896129fb9acf04e9785774bfb0dc5947c"
dependencies = [
"ra-ap-rustc_lexer",
"rustc-literal-escaper 0.0.5",
@@ -1924,9 +1906,9 @@
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a181cf7943dc16e888046584d6172be95818811b25d695dbacbb4dd71973cc3"
+checksum = "cf944dce80137195528f89a576f70153c2060a6f8ca49c3fa9f55f9da14ab937"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.1.1",
@@ -1937,9 +1919,9 @@
[[package]]
name = "ra-ap-rustc_type_ir"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87c99f33be18d9e50cefef5442822da1f0b416e9a17a483879a9704e08a6a6e6"
+checksum = "1bfe2722b20bc889a9d7711bd3a1f4f7b082940491241615aa643c17e0deffec"
dependencies = [
"arrayvec",
"bitflags 2.9.4",
@@ -1957,9 +1939,9 @@
[[package]]
name = "ra-ap-rustc_type_ir_macros"
-version = "0.133.0"
+version = "0.137.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77b162d65e058abfc058e6b67ae68156cc282fbd78da148c1a7ec77b4230661e"
+checksum = "6fad1527df26aaa77367393fae86f42818b33e02b3737a19f3846d1c7671e7f9"
dependencies = [
"proc-macro2",
"quote",
@@ -2993,24 +2975,6 @@
[[package]]
name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
diff --git a/Cargo.toml b/Cargo.toml
index f94fd37..ecb2686 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,8 +37,6 @@
[patch.'crates-io']
# rowan = { path = "../rowan" }
-# chalk-ir = { path = "../chalk/chalk-ir" }
-# chalk-derive = { path = "../chalk/chalk-derive" }
# line-index = { path = "lib/line-index" }
# la-arena = { path = "lib/la-arena" }
# lsp-server = { path = "lib/lsp-server" }
@@ -88,14 +86,14 @@
vfs = { path = "./crates/vfs", version = "0.0.0" }
edition = { path = "./crates/edition", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.133", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.133", default-features = false }
-ra-ap-rustc_index = { version = "0.133", default-features = false }
-ra-ap-rustc_abi = { version = "0.133", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.133", default-features = false }
-ra-ap-rustc_ast_ir = { version = "0.133", default-features = false }
-ra-ap-rustc_type_ir = { version = "0.133", default-features = false }
-ra-ap-rustc_next_trait_solver = { version = "0.133", default-features = false }
+ra-ap-rustc_lexer = { version = "0.137", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.137", default-features = false }
+ra-ap-rustc_index = { version = "0.137", default-features = false }
+ra-ap-rustc_abi = { version = "0.137", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.137", default-features = false }
+ra-ap-rustc_ast_ir = { version = "0.137", default-features = false }
+ra-ap-rustc_type_ir = { version = "0.137", default-features = false }
+ra-ap-rustc_next_trait_solver = { version = "0.137", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
@@ -110,8 +108,6 @@
bitflags = "2.9.1"
cargo_metadata = "0.21.0"
camino = "1.1.10"
-chalk-ir = "0.104.0"
-chalk-derive = "0.104.0"
crossbeam-channel = "0.5.15"
dissimilar = "1.0.10"
dot = "0.1.4"
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index af95f86..e17969b 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -29,5 +29,8 @@
syntax-bridge.workspace = true
syntax.workspace = true
+# tt is needed for testing
+cfg = { path = ".", default-features = false, features = ["tt"] }
+
[lints]
workspace = true
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 906106c..b1ec4c2 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -115,6 +115,13 @@
pub fn shrink_to_fit(&mut self) {
self.enabled.shrink_to_fit();
}
+
+ pub fn append(&mut self, other: CfgOptions) {
+ // Do not call `insert_any_atom()`, as it'll check for `true` and `false`, but this is not
+ // needed since we already checked for that when constructing `other`. Furthermore, this
+ // will always err, as `other` inevitably contains `true` (just as we do).
+ self.enabled.extend(other.enabled);
+ }
}
impl Extend<CfgAtom> for CfgOptions {
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index ec65633..378a0f0 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -24,8 +24,6 @@
tracing.workspace = true
rustc-hash.workspace = true
scoped-tls = "1.0.1"
-chalk-ir.workspace = true
-chalk-derive.workspace = true
la-arena.workspace = true
triomphe.workspace = true
typed-arena = "2.0.2"
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
deleted file mode 100644
index 706bbe8..0000000
--- a/crates/hir-ty/src/builder.rs
+++ /dev/null
@@ -1,398 +0,0 @@
-//! `TyBuilder`, a helper for building instances of `Ty` and related types.
-
-use chalk_ir::{
- AdtId, DebruijnIndex, Scalar,
- cast::{Cast, CastTo, Caster},
-};
-use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
-use smallvec::SmallVec;
-
-use crate::{
- BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
- TraitRef, Ty, TyDefId, TyExt, TyKind,
- consteval::unknown_const_as_generic,
- db::HirDatabase,
- error_lifetime,
- generics::generics,
- infer::unify::InferenceTable,
- next_solver::{
- DbInterner, EarlyBinder,
- mapping::{ChalkToNextSolver, NextSolverToChalk},
- },
- primitive, to_assoc_type_id, to_chalk_trait_id,
-};
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ParamKind {
- Type,
- Lifetime,
- Const(Ty),
-}
-
-/// This is a builder for `Ty` or anything that needs a `Substitution`.
-pub struct TyBuilder<D> {
- /// The `data` field is used to keep track of what we're building (e.g. an
- /// ADT, a `TraitRef`, ...).
- data: D,
- vec: SmallVec<[GenericArg; 2]>,
- param_kinds: SmallVec<[ParamKind; 2]>,
- parent_subst: Substitution,
-}
-
-impl<A> TyBuilder<A> {
- fn with_data<B>(self, data: B) -> TyBuilder<B> {
- TyBuilder {
- data,
- vec: self.vec,
- param_kinds: self.param_kinds,
- parent_subst: self.parent_subst,
- }
- }
-}
-
-impl<D> TyBuilder<D> {
- fn new(
- data: D,
- param_kinds: SmallVec<[ParamKind; 2]>,
- parent_subst: Option<Substitution>,
- ) -> Self {
- let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
- Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
- }
-
- fn new_empty(data: D) -> Self {
- TyBuilder::new(data, SmallVec::new(), None)
- }
-
- fn build_internal(self) -> (D, Substitution) {
- 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);
- }
- let subst = Substitution::from_iter(
- Interner,
- self.parent_subst.iter(Interner).cloned().chain(self.vec),
- );
- (self.data, subst)
- }
-
- pub fn build_into_subst(self) -> Substitution {
- self.build_internal().1
- }
-
- pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
- assert!(self.remaining() > 0);
- let arg = arg.cast(Interner);
- let expected_kind = &self.param_kinds[self.vec.len()];
-
- let arg_kind = match arg.data(Interner) {
- GenericArgData::Ty(_) => ParamKind::Type,
- GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
- GenericArgData::Const(c) => {
- let c = c.data(Interner);
- ParamKind::Const(c.ty.clone())
- }
- };
- assert_eq!(*expected_kind, arg_kind);
-
- self.vec.push(arg);
-
- self
- }
-
- pub fn remaining(&self) -> usize {
- self.param_kinds.len() - self.vec.len()
- }
-
- pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
- // self.fill is inlined to make borrow checker happy
- let mut this = self;
- let other = &this.param_kinds[this.vec.len()..];
- let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
- ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
- ParamKind::Const(ty) => {
- BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
- }
- ParamKind::Lifetime => {
- BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
- }
- });
- this.vec.extend(filler.take(this.remaining()).casted(Interner));
- assert_eq!(this.remaining(), 0);
- this
- }
-
- pub fn fill_with_unknown(self) -> Self {
- let interner = DbInterner::conjure();
- // self.fill is inlined to make borrow checker happy
- let mut this = self;
- let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
- ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
- ParamKind::Const(ty) => {
- unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
- }
- ParamKind::Lifetime => error_lifetime().cast(Interner),
- });
- this.vec.extend(filler.casted(Interner));
- assert_eq!(this.remaining(), 0);
- this
- }
-
- #[tracing::instrument(skip_all)]
- pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
- self.fill(|x| {
- match x {
- ParamKind::Type => crate::next_solver::GenericArg::Ty(table.next_ty_var()),
- ParamKind::Const(_) => table.next_const_var().into(),
- ParamKind::Lifetime => table.next_region_var().into(),
- }
- .to_chalk(table.interner())
- })
- }
-
- pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
- self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
- assert_eq!(self.remaining(), 0);
- self
- }
-
- fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
- match (a.data(Interner), e) {
- (GenericArgData::Ty(_), ParamKind::Type)
- | (GenericArgData::Const(_), ParamKind::Const(_))
- | (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (),
- _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
- }
- }
-}
-
-impl TyBuilder<()> {
- pub fn unit() -> Ty {
- TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
- }
-
- // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well
- pub fn discr_ty() -> Ty {
- TyKind::Scalar(chalk_ir::Scalar::Int(chalk_ir::IntTy::I128)).intern(Interner)
- }
-
- pub fn bool() -> Ty {
- TyKind::Scalar(chalk_ir::Scalar::Bool).intern(Interner)
- }
-
- pub fn usize() -> Ty {
- TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
- }
-
- pub fn fn_ptr(sig: CallableSig) -> Ty {
- TyKind::Function(sig.to_fn_ptr()).intern(Interner)
- }
-
- pub fn builtin(builtin: BuiltinType) -> Ty {
- match builtin {
- BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
- BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
- BuiltinType::Str => TyKind::Str.intern(Interner),
- BuiltinType::Int(t) => {
- TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
- }
- BuiltinType::Uint(t) => {
- TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
- }
- BuiltinType::Float(t) => {
- TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
- }
- }
- }
-
- pub fn slice(argument: Ty) -> Ty {
- TyKind::Slice(argument).intern(Interner)
- }
-
- pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
- let params = generics(db, def.into());
- params.placeholder_subst(db)
- }
-
- pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
- let interner = DbInterner::conjure();
- let params = generics(db, def.into());
- Substitution::from_iter(
- Interner,
- params.iter_id().map(|id| match id {
- GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
- GenericParamId::ConstParamId(id) => {
- unknown_const_as_generic(db.const_param_ty_ns(id))
- .to_chalk(interner)
- .cast(Interner)
- }
- GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
- }),
- )
- }
-
- #[tracing::instrument(skip_all)]
- pub fn subst_for_def(
- db: &dyn HirDatabase,
- def: impl Into<GenericDefId>,
- parent_subst: Option<Substitution>,
- ) -> TyBuilder<()> {
- let generics = generics(db, def.into());
- assert!(generics.parent_generics().is_some() == parent_subst.is_some());
- let params = generics
- .iter_self()
- .map(|(id, _data)| match id {
- GenericParamId::TypeParamId(_) => ParamKind::Type,
- GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)),
- GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
- })
- .collect();
- TyBuilder::new((), params, parent_subst)
- }
-
- pub fn build(self) -> Substitution {
- let ((), subst) = self.build_internal();
- subst
- }
-}
-
-impl TyBuilder<hir_def::AdtId> {
- pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
- TyBuilder::subst_for_def(db, def, None).with_data(def)
- }
-
- pub fn fill_with_defaults(
- mut self,
- db: &dyn HirDatabase,
- mut fallback: impl FnMut() -> Ty,
- ) -> Self {
- let interner = DbInterner::conjure();
- // Note that we're building ADT, so we never have parent generic parameters.
- let defaults = db.generic_defaults(self.data.into());
-
- if let Some(defaults) = defaults.get(self.vec.len()..) {
- for default_ty in defaults {
- // NOTE(skip_binders): we only check if the arg type is error type.
- if let Some(x) = default_ty.skip_binders().ty(Interner)
- && x.is_unknown()
- {
- self.vec.push(fallback().cast(Interner));
- continue;
- }
- // Each default can only depend on the previous parameters.
- self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
- }
- }
-
- // The defaults may be missing if no param has default, so fill that.
- let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
- ParamKind::Type => fallback().cast(Interner),
- ParamKind::Const(ty) => {
- unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
- }
- ParamKind::Lifetime => error_lifetime().cast(Interner),
- });
- self.vec.extend(filler.casted(Interner));
-
- self
- }
-
- pub fn build(self) -> Ty {
- let (adt, subst) = self.build_internal();
- TyKind::Adt(AdtId(adt), subst).intern(Interner)
- }
-}
-
-pub struct Tuple(usize);
-impl TyBuilder<Tuple> {
- pub fn tuple(size: usize) -> TyBuilder<Tuple> {
- TyBuilder::new(Tuple(size), std::iter::repeat_n(ParamKind::Type, size).collect(), None)
- }
-
- pub fn build(self) -> Ty {
- let (Tuple(size), subst) = self.build_internal();
- TyKind::Tuple(size, subst).intern(Interner)
- }
-
- pub fn tuple_with<I>(elements: I) -> Ty
- where
- I: IntoIterator<Item = Ty>,
- <I as IntoIterator>::IntoIter: ExactSizeIterator,
- {
- let elements = elements.into_iter();
- let len = elements.len();
- let mut b =
- TyBuilder::new(Tuple(len), std::iter::repeat_n(ParamKind::Type, len).collect(), None);
- for e in elements {
- b = b.push(e);
- }
- b.build()
- }
-}
-
-impl TyBuilder<TraitId> {
- pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
- TyBuilder::subst_for_def(db, def, None).with_data(def)
- }
-
- pub fn build(self) -> TraitRef {
- let (trait_id, substitution) = self.build_internal();
- TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
- }
-}
-
-impl TyBuilder<TypeAliasId> {
- pub fn assoc_type_projection(
- db: &dyn HirDatabase,
- def: TypeAliasId,
- parent_subst: Option<Substitution>,
- ) -> TyBuilder<TypeAliasId> {
- TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
- }
-
- pub fn build(self) -> ProjectionTy {
- let (type_alias, substitution) = self.build_internal();
- ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
- }
-}
-
-impl<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>> TyBuilder<EarlyBinder<'db, T>> {
- pub fn build(self, interner: DbInterner<'db>) -> T {
- let (b, subst) = self.build_internal();
- let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner);
- b.instantiate(interner, args)
- }
-}
-
-impl<'db> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
- pub fn def_ty(
- db: &'db dyn HirDatabase,
- def: TyDefId,
- parent_subst: Option<Substitution>,
- ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
- let poly_ty = db.ty(def);
- let id: GenericDefId = match def {
- TyDefId::BuiltinType(_) => {
- assert!(parent_subst.is_none());
- return TyBuilder::new_empty(poly_ty);
- }
- TyDefId::AdtId(id) => id.into(),
- TyDefId::TypeAliasId(id) => id.into(),
- };
- TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
- }
-
- pub fn impl_self_ty(
- db: &'db dyn HirDatabase,
- def: hir_def::ImplId,
- ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
- TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
- }
-}
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
deleted file mode 100644
index 3d06b52..0000000
--- a/crates/hir-ty/src/chalk_db.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-//! The implementation of `RustIrDatabase` for Chalk, which provides information
-//! about the code that Chalk needs.
-use hir_def::{CallableDefId, GenericDefId};
-
-use crate::{Interner, db::HirDatabase, mapping::from_chalk};
-
-pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
-pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
-pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
-pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
-pub(crate) type Variances = chalk_ir::Variances<Interner>;
-
-impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
- fn fn_def_variance(
- &self,
- fn_def_id: chalk_ir::FnDefId<Interner>,
- ) -> chalk_ir::Variances<Interner> {
- HirDatabase::fn_def_variance(*self, from_chalk(*self, fn_def_id))
- }
-
- fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
- HirDatabase::adt_variance(*self, adt_id.0)
- }
-}
-
-pub(crate) fn fn_def_variance_query(
- db: &dyn HirDatabase,
- callable_def: CallableDefId,
-) -> Variances {
- Variances::from_iter(
- Interner,
- db.variances_of(GenericDefId::from_callable(db, callable_def))
- .as_deref()
- .unwrap_or_default()
- .iter()
- .map(|v| match v {
- crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
- crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
- crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
- crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
- }),
- )
-}
-
-pub(crate) fn adt_variance_query(db: &dyn HirDatabase, adt_id: hir_def::AdtId) -> Variances {
- Variances::from_iter(
- Interner,
- db.variances_of(adt_id.into()).as_deref().unwrap_or_default().iter().map(|v| match v {
- crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
- crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
- crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
- crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
- }),
- )
-}
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
deleted file mode 100644
index e996037..0000000
--- a/crates/hir-ty/src/chalk_ext.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-//! Various extensions traits for Chalk types.
-
-use chalk_ir::Mutability;
-use hir_def::{FunctionId, ItemContainerId, Lookup, TraitId};
-
-use crate::{
- AdtId, Binders, CallableDefId, CallableSig, DynTy, Interner, Lifetime, ProjectionTy,
- Substitution, ToChalk, TraitRef, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase,
- from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id,
- utils::ClosureSubst,
-};
-
-pub(crate) trait TyExt {
- fn is_unit(&self) -> bool;
- fn is_unknown(&self) -> bool;
- fn contains_unknown(&self) -> bool;
-
- fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
- fn as_tuple(&self) -> Option<&Substitution>;
- fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
- fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
-
- fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
- fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
-
- fn strip_references(&self) -> &Ty;
-
- /// If this is a `dyn Trait`, returns that trait.
- fn dyn_trait(&self) -> Option<TraitId>;
-}
-
-impl TyExt for Ty {
- fn is_unit(&self) -> bool {
- matches!(self.kind(Interner), TyKind::Tuple(0, _))
- }
-
- fn is_unknown(&self) -> bool {
- matches!(self.kind(Interner), TyKind::Error)
- }
-
- fn contains_unknown(&self) -> bool {
- self.data(Interner).flags.contains(TypeFlags::HAS_ERROR)
- }
-
- fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
- match self.kind(Interner) {
- TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
- _ => None,
- }
- }
-
- fn as_tuple(&self) -> Option<&Substitution> {
- match self.kind(Interner) {
- TyKind::Tuple(_, substs) => Some(substs),
- _ => None,
- }
- }
-
- fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
- match self.callable_def(db) {
- Some(CallableDefId::FunctionId(func)) => Some(func),
- Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None,
- }
- }
-
- fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
- match self.kind(Interner) {
- TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
- _ => None,
- }
- }
-
- fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
- match self.kind(Interner) {
- &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
- _ => None,
- }
- }
-
- fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
- match self.kind(Interner) {
- TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
- TyKind::FnDef(def, parameters) => Some(CallableSig::from_def(db, *def, parameters)),
- TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty(db).callable_sig(db),
- _ => None,
- }
- }
-
- fn dyn_trait(&self) -> Option<TraitId> {
- let trait_ref = match self.kind(Interner) {
- // The principal trait bound should be the first element of the bounds. This is an
- // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
- // FIXME: dyn types may not have principal trait and we don't want to return auto trait
- // here.
- TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().first().and_then(|b| {
- match b.skip_binders() {
- WhereClause::Implemented(trait_ref) => Some(trait_ref),
- _ => None,
- }
- }),
- _ => None,
- }?;
- Some(from_chalk_trait_id(trait_ref.trait_id))
- }
-
- fn strip_references(&self) -> &Ty {
- let mut t: &Ty = self;
- while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) {
- t = ty;
- }
- t
- }
-}
-
-pub trait ProjectionTyExt {
- fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
- fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
- fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
-}
-
-impl ProjectionTyExt for ProjectionTy {
- fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
- // FIXME: something like `Split` trait from chalk-solve might be nice.
- let generics = generics(db, from_assoc_type_id(self.associated_ty_id).into());
- let parent_len = generics.parent_generics().map_or(0, |g| g.len_self());
- let substitution =
- Substitution::from_iter(Interner, self.substitution.iter(Interner).take(parent_len));
- TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
- }
-
- fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
- match from_assoc_type_id(self.associated_ty_id).lookup(db).container {
- ItemContainerId::TraitId(it) => it,
- _ => panic!("projection ty without parent trait"),
- }
- }
-
- fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
- self.trait_ref(db).self_type_parameter(Interner)
- }
-}
-
-pub(crate) trait DynTyExt {
- fn principal(&self) -> Option<Binders<Binders<&TraitRef>>>;
-}
-
-impl DynTyExt for DynTy {
- fn principal(&self) -> Option<Binders<Binders<&TraitRef>>> {
- self.bounds.as_ref().filter_map(|bounds| {
- bounds.interned().first().and_then(|b| {
- b.as_ref().filter_map(|b| match b {
- crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
- _ => None,
- })
- })
- })
- }
-}
-
-pub trait TraitRefExt {
- fn hir_trait_id(&self) -> TraitId;
-}
-
-impl TraitRefExt for TraitRef {
- fn hir_trait_id(&self) -> TraitId {
- from_chalk_trait_id(self.trait_id)
- }
-}
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 002e082..18ebe7d 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -5,76 +5,29 @@
use base_db::Crate;
use hir_def::{
- EnumVariantId, GeneralConstId,
- expr_store::{Body, HygieneId, path::Path},
+ EnumVariantId, GeneralConstId, HasModule, StaticId,
+ expr_store::Body,
hir::{Expr, ExprId},
- resolver::{Resolver, ValueNs},
type_ref::LiteralConstRef,
};
-use hir_def::{HasModule, StaticId};
use hir_expand::Lookup;
-use rustc_type_ir::{UnevaluatedConst, inherent::IntoKind};
-use stdx::never;
+use rustc_type_ir::inherent::IntoKind;
use triomphe::Arc;
use crate::{
- MemoryMap, TraitEnvironment,
+ LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext,
db::HirDatabase,
display::DisplayTarget,
- generics::Generics,
infer::InferenceContext,
mir::{MirEvalError, MirLowerError},
next_solver::{
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
- ParamConst, SolverDefId, Ty, ValueConst,
+ SolverDefId, Ty, ValueConst,
},
};
use super::mir::{interpret_mir, lower_to_mir, pad16};
-pub(crate) fn path_to_const<'a, 'g>(
- db: &'a dyn HirDatabase,
- resolver: &Resolver<'a>,
- path: &Path,
- args: impl FnOnce() -> &'g Generics,
- _expected_ty: Ty<'a>,
-) -> Option<Const<'a>> {
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
- Some(ValueNs::GenericParam(p)) => {
- let args = args();
- match args
- .type_or_const_param(p.into())
- .and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone())))
- {
- Some((idx, _param)) => {
- Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p }))
- }
- None => {
- never!(
- "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
- args,
- path,
- p
- );
- None
- }
- }
- }
- Some(ValueNs::ConstId(c)) => {
- let args = GenericArgs::new_from_iter(interner, []);
- Some(Const::new(
- interner,
- rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
- SolverDefId::ConstId(c),
- args,
- )),
- ))
- }
- _ => None,
- }
-}
-
pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> {
Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
}
@@ -280,8 +233,14 @@
return unknown_const(infer[expr]);
}
if let Expr::Path(p) = &ctx.body[expr] {
- let resolver = &ctx.resolver;
- if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) {
+ let mut ctx = TyLoweringContext::new(
+ ctx.db,
+ &ctx.resolver,
+ ctx.body,
+ ctx.generic_def,
+ LifetimeElisionKind::Infer,
+ );
+ if let Some(c) = ctx.path_to_const(p) {
return c;
}
}
diff --git a/crates/hir-ty/src/consteval_chalk.rs b/crates/hir-ty/src/consteval_chalk.rs
deleted file mode 100644
index 07b783e..0000000
--- a/crates/hir-ty/src/consteval_chalk.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//! Constant evaluation details
-
-use base_db::Crate;
-use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast};
-use hir_def::{
- expr_store::{HygieneId, path::Path},
- resolver::{Resolver, ValueNs},
- type_ref::LiteralConstRef,
-};
-use stdx::never;
-
-use crate::{
- Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution,
- TraitEnvironment, Ty,
- db::HirDatabase,
- generics::Generics,
- lower::ParamLoweringMode,
- next_solver::{DbInterner, mapping::ChalkToNextSolver},
- to_placeholder_idx,
-};
-
-pub(crate) fn path_to_const<'g>(
- db: &dyn HirDatabase,
- resolver: &Resolver<'_>,
- path: &Path,
- mode: ParamLoweringMode,
- args: impl FnOnce() -> &'g Generics,
- debruijn: DebruijnIndex,
- expected_ty: Ty,
-) -> Option<Const> {
- match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
- Some(ValueNs::GenericParam(p)) => {
- let ty = db.const_param_ty(p);
- let args = args();
- let value = match mode {
- ParamLoweringMode::Placeholder => {
- let idx = args.type_or_const_param_idx(p.into()).unwrap();
- ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32))
- }
- ParamLoweringMode::Variable => match args.type_or_const_param_idx(p.into()) {
- Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
- None => {
- never!(
- "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
- args,
- path,
- p
- );
- return None;
- }
- },
- };
- Some(ConstData { ty, value }.intern(Interner))
- }
- Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
- ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
- expected_ty,
- )),
- // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors.
- _ => None,
- }
-}
-
-pub(crate) fn unknown_const(ty: Ty) -> Const {
- ConstData {
- ty,
- value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
- }
- .intern(Interner)
-}
-
-pub(crate) fn unknown_const_as_generic(ty: Ty) -> GenericArg {
- unknown_const(ty).cast(Interner)
-}
-
-/// Interns a constant scalar with the given type
-pub(crate) fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const {
- ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
- .intern(Interner)
-}
-
-/// Interns a constant scalar with the given type
-pub(crate) fn intern_const_ref(
- db: &dyn HirDatabase,
- value: &LiteralConstRef,
- ty: Ty,
- krate: Crate,
-) -> Const {
- let interner = DbInterner::new_with(db, Some(krate), None);
- let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate));
- let bytes = match value {
- LiteralConstRef::Int(i) => {
- // FIXME: We should handle failure of layout better.
- let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
- ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
- }
- LiteralConstRef::UInt(i) => {
- let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
- ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
- }
- LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()),
- LiteralConstRef::Char(c) => {
- ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default())
- }
- LiteralConstRef::Unknown => ConstScalar::Unknown,
- };
- intern_const_scalar(bytes, ty)
-}
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 4b33c8a..9b58abb 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -1,8 +1,7 @@
//! The home of `HirDatabase`, which is the Salsa database containing all the
//! type inference-related queries.
-use base_db::Crate;
-use base_db::target::TargetLoadError;
+use base_db::{Crate, target::TargetLoadError};
use hir_def::{
AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
@@ -16,15 +15,14 @@
use triomphe::Arc;
use crate::{
- Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId,
- chalk_db,
+ ImplTraitId, InferenceResult, TraitEnvironment, TyDefId, ValueTyDefId,
consteval::ConstEvalError,
dyn_compatibility::DynCompatibilityViolation,
layout::{Layout, LayoutError},
- lower::{Diagnostics, GenericDefaults, GenericPredicates},
+ lower::{Diagnostics, GenericDefaults, GenericPredicates, ImplTraits},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError},
- traits::NextTraitSolveResult,
+ next_solver::{Const, EarlyBinder, GenericArgs, PolyFnSig, TraitRef, Ty, VariancesOf},
};
#[query_group::query_group]
@@ -53,7 +51,7 @@
fn monomorphized_mir_body<'db>(
&'db self,
def: DefWithBodyId,
- subst: crate::next_solver::GenericArgs<'db>,
+ subst: GenericArgs<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
@@ -61,7 +59,7 @@
fn monomorphized_mir_body_for_closure<'db>(
&'db self,
def: InternedClosureId,
- subst: crate::next_solver::GenericArgs<'db>,
+ subst: GenericArgs<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
@@ -77,16 +75,13 @@
fn const_eval<'db>(
&'db self,
def: GeneralConstId,
- subst: crate::next_solver::GenericArgs<'db>,
+ subst: GenericArgs<'db>,
trait_env: Option<Arc<TraitEnvironment<'db>>>,
- ) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
+ ) -> Result<Const<'db>, ConstEvalError<'db>>;
#[salsa::invoke(crate::consteval::const_eval_static_query)]
#[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)]
- fn const_eval_static<'db>(
- &'db self,
- def: StaticId,
- ) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
+ fn const_eval_static<'db>(&'db self, def: StaticId) -> Result<Const<'db>, ConstEvalError<'db>>;
#[salsa::invoke(crate::consteval::const_eval_discriminant_variant)]
#[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)]
@@ -96,12 +91,13 @@
) -> Result<i128, ConstEvalError<'db>>;
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
+ #[salsa::transparent]
fn lookup_impl_method<'db>(
&'db self,
env: Arc<TraitEnvironment<'db>>,
func: FunctionId,
- fn_subst: crate::next_solver::GenericArgs<'db>,
- ) -> (FunctionId, crate::next_solver::GenericArgs<'db>);
+ fn_subst: GenericArgs<'db>,
+ ) -> (FunctionId, GenericArgs<'db>);
// endregion:mir
@@ -110,7 +106,7 @@
fn layout_of_adt<'db>(
&'db self,
def: AdtId,
- args: crate::next_solver::GenericArgs<'db>,
+ args: GenericArgs<'db>,
trait_env: Arc<TraitEnvironment<'db>>,
) -> Result<Arc<Layout>, LayoutError>;
@@ -118,7 +114,7 @@
#[salsa::cycle(cycle_result = crate::layout::layout_of_ty_cycle_result)]
fn layout_of_ty<'db>(
&'db self,
- ty: crate::next_solver::Ty<'db>,
+ ty: Ty<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> Result<Arc<Layout>, LayoutError>;
@@ -128,149 +124,130 @@
#[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
- #[salsa::invoke(crate::lower_nextsolver::ty_query)]
+ #[salsa::invoke(crate::lower::ty_query)]
#[salsa::transparent]
- fn ty<'db>(
- &'db self,
- def: TyDefId,
- ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
+ fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>>;
- #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
- #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
+ #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
+ #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)]
fn type_for_type_alias_with_diagnostics<'db>(
&'db self,
def: TypeAliasId,
- ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
+ ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics);
/// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
/// a `StructId` or `EnumVariantId` with a record constructor.
- #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
- fn value_ty<'db>(
- &'db self,
- def: ValueTyDefId,
- ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
+ #[salsa::invoke(crate::lower::value_ty_query)]
+ fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option<EarlyBinder<'db, Ty<'db>>>;
- #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
- #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
+ #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
+ #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)]
fn impl_self_ty_with_diagnostics<'db>(
&'db self,
def: ImplId,
- ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
+ ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics);
- #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
+ #[salsa::invoke(crate::lower::impl_self_ty_query)]
#[salsa::transparent]
- fn impl_self_ty<'db>(
- &'db self,
- def: ImplId,
- ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
+ fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>;
// FIXME: Make this a non-interned query.
- #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
- #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)]
- fn const_param_ty_with_diagnostics<'db>(
- &'db self,
- def: ConstParamId,
- ) -> (crate::next_solver::Ty<'db>, Diagnostics);
+ #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
+ #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
+ fn const_param_ty_with_diagnostics<'db>(&'db self, def: ConstParamId)
+ -> (Ty<'db>, Diagnostics);
- // FIXME: Make this a non-interned query.
- #[salsa::invoke_interned(crate::lower::const_param_ty_query)]
- #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)]
- fn const_param_ty(&self, def: ConstParamId) -> Ty;
+ #[salsa::invoke(crate::lower::const_param_ty_query)]
+ #[salsa::transparent]
+ fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> Ty<'db>;
- #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
+ #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
fn impl_trait_with_diagnostics<'db>(
&'db self,
def: ImplId,
- ) -> Option<(
- crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
- Diagnostics,
- )>;
+ ) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)>;
- #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
+ #[salsa::invoke(crate::lower::impl_trait_query)]
#[salsa::transparent]
- fn impl_trait<'db>(
- &'db self,
- def: ImplId,
- ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
+ fn impl_trait<'db>(&'db self, def: ImplId) -> Option<EarlyBinder<'db, TraitRef<'db>>>;
- #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
+ #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
fn field_types_with_diagnostics<'db>(
&'db self,
var: VariantId,
- ) -> (
- Arc<
- ArenaMap<
- LocalFieldId,
- crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
- >,
- >,
- Diagnostics,
- );
+ ) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics);
#[salsa::invoke(crate::lower::field_types_query)]
#[salsa::transparent]
- fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
+ fn field_types<'db>(
+ &'db self,
+ var: VariantId,
+ ) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>;
- #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
+ #[salsa::invoke(crate::lower::callable_item_signature_query)]
fn callable_item_signature<'db>(
&'db self,
def: CallableDefId,
- ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
+ ) -> EarlyBinder<'db, PolyFnSig<'db>>;
#[salsa::invoke(crate::lower::return_type_impl_traits)]
- fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
+ fn return_type_impl_traits<'db>(
+ &'db self,
+ def: FunctionId,
+ ) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>>;
#[salsa::invoke(crate::lower::type_alias_impl_traits)]
- fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>;
+ fn type_alias_impl_traits<'db>(
+ &'db self,
+ def: TypeAliasId,
+ ) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>>;
- #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
- #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)]
- fn generic_predicates_for_param(
- &self,
- def: GenericDefId,
- param_id: TypeOrConstParamId,
- assoc_name: Option<Name>,
- ) -> GenericPredicates;
-
- #[salsa::invoke(crate::lower::generic_predicates_query)]
- fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
-
- #[salsa::invoke(
- crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
- )]
+ #[salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)]
fn generic_predicates_without_parent_with_diagnostics<'db>(
&'db self,
def: GenericDefId,
- ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
+ ) -> (GenericPredicates<'db>, Diagnostics);
- #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
+ #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
#[salsa::transparent]
fn generic_predicates_without_parent<'db>(
&'db self,
def: GenericDefId,
- ) -> crate::lower_nextsolver::GenericPredicates<'db>;
+ ) -> GenericPredicates<'db>;
- #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)]
+ #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
+ #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)]
+ fn generic_predicates_for_param<'db>(
+ &'db self,
+ def: GenericDefId,
+ param_id: TypeOrConstParamId,
+ assoc_name: Option<Name>,
+ ) -> GenericPredicates<'db>;
+
+ #[salsa::invoke(crate::lower::generic_predicates_query)]
+ fn generic_predicates<'db>(&'db self, def: GenericDefId) -> GenericPredicates<'db>;
+
+ #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
#[salsa::transparent]
fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId)
-> Arc<TraitEnvironment<'db>>;
- #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)]
+ #[salsa::invoke(crate::lower::trait_environment_query)]
fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>;
#[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
#[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)]
- fn generic_defaults_with_diagnostics(
- &self,
+ fn generic_defaults_with_diagnostics<'db>(
+ &'db self,
def: GenericDefId,
- ) -> (GenericDefaults, Diagnostics);
+ ) -> (GenericDefaults<'db>, Diagnostics);
/// This returns an empty list if no parameter has default.
///
/// The binders of the returned defaults are only up to (not including) this parameter.
#[salsa::invoke(crate::lower::generic_defaults_query)]
#[salsa::transparent]
- fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
+ fn generic_defaults<'db>(&'db self, def: GenericDefId) -> GenericDefaults<'db>;
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: Crate) -> Arc<InherentImpls>;
@@ -298,9 +275,9 @@
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc<TraitImpls>]>;
- // Interned IDs for Chalk integration
+ // Interned IDs for solver integration
#[salsa::interned]
- fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
+ fn intern_impl_trait_id(&self, id: ImplTraitId<'_>) -> InternedOpaqueTyId;
#[salsa::interned]
fn intern_closure(&self, id: InternedClosure) -> InternedClosureId;
@@ -308,95 +285,13 @@
#[salsa::interned]
fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId;
- #[salsa::invoke(chalk_db::fn_def_variance_query)]
- fn fn_def_variance(&self, fn_def_id: CallableDefId) -> chalk_db::Variances;
-
- #[salsa::invoke(chalk_db::adt_variance_query)]
- fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances;
-
#[salsa::invoke(crate::variance::variances_of)]
#[salsa::cycle(
// cycle_fn = crate::variance::variances_of_cycle_fn,
// cycle_initial = crate::variance::variances_of_cycle_initial,
cycle_result = crate::variance::variances_of_cycle_initial,
)]
- fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
-
- #[salsa::invoke(crate::traits::normalize_projection_query)]
- #[salsa::transparent]
- fn normalize_projection(
- &self,
- projection: crate::ProjectionTy,
- env: Arc<TraitEnvironment<'_>>,
- ) -> Ty;
-
- #[salsa::invoke(crate::traits::trait_solve_query)]
- #[salsa::transparent]
- fn trait_solve(
- &self,
- krate: Crate,
- block: Option<BlockId>,
- goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
- ) -> NextTraitSolveResult;
-
- // next trait solver
-
- #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)]
- #[salsa::transparent]
- fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>;
-
- #[salsa::invoke(crate::lower_nextsolver::field_types_query)]
- #[salsa::transparent]
- fn field_types_ns<'db>(
- &'db self,
- var: VariantId,
- ) -> Arc<
- ArenaMap<LocalFieldId, crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>,
- >;
-
- #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)]
- fn return_type_impl_traits_ns<'db>(
- &'db self,
- def: FunctionId,
- ) -> Option<Arc<crate::next_solver::EarlyBinder<'db, crate::lower_nextsolver::ImplTraits<'db>>>>;
-
- #[salsa::invoke(crate::lower_nextsolver::type_alias_impl_traits)]
- fn type_alias_impl_traits_ns<'db>(
- &'db self,
- def: TypeAliasId,
- ) -> Option<Arc<crate::next_solver::EarlyBinder<'db, crate::lower_nextsolver::ImplTraits<'db>>>>;
-
- #[salsa::invoke(crate::lower_nextsolver::generic_predicates_for_param_query)]
- #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_predicates_for_param_cycle_result)]
- fn generic_predicates_for_param_ns<'db>(
- &'db self,
- def: GenericDefId,
- param_id: TypeOrConstParamId,
- assoc_name: Option<Name>,
- ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
- #[salsa::invoke(crate::lower_nextsolver::generic_predicates_query)]
- fn generic_predicates_ns<'db>(
- &'db self,
- def: GenericDefId,
- ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
- #[salsa::invoke(crate::lower_nextsolver::generic_defaults_with_diagnostics_query)]
- #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_defaults_with_diagnostics_cycle_result)]
- fn generic_defaults_ns_with_diagnostics<'db>(
- &'db self,
- def: GenericDefId,
- ) -> (crate::lower_nextsolver::GenericDefaults<'db>, Diagnostics);
-
- /// This returns an empty list if no parameter has default.
- ///
- /// The binders of the returned defaults are only up to (not including) this parameter.
- #[salsa::invoke(crate::lower_nextsolver::generic_defaults_query)]
- #[salsa::transparent]
- fn generic_defaults_ns<'db>(
- &'db self,
- def: GenericDefId,
- ) -> crate::lower_nextsolver::GenericDefaults<'db>;
+ fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db>;
}
#[test]
@@ -427,7 +322,7 @@
#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
#[derive(PartialOrd, Ord)]
pub struct InternedOpaqueTyId {
- pub loc: ImplTraitId,
+ pub loc: ImplTraitId<'db>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 7b6fb99..0eca0c0 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -15,6 +15,7 @@
use itertools::Itertools;
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor;
+use rustc_type_ir::inherent::{AdtDef, IntoKind};
use syntax::{
AstNode,
ast::{self, UnaryOp},
@@ -23,16 +24,18 @@
use triomphe::Arc;
use typed_arena::Arena;
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
- Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind,
+ Adjust, InferenceResult, TraitEnvironment,
db::HirDatabase,
diagnostics::match_check::{
self,
pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
},
display::{DisplayTarget, HirDisplay},
+ next_solver::{
+ DbInterner, Ty, TyKind, TypingMode,
+ infer::{DbInternerInferExt, InferCtxt},
+ },
};
pub(crate) use hir_def::{
@@ -77,6 +80,8 @@
let body = db.body(owner);
let env = db.trait_environment_for_body(owner);
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+ let infcx =
+ interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into()));
let mut validator = ExprValidator {
owner,
body,
@@ -84,9 +89,9 @@
diagnostics: Vec::new(),
validate_lints,
env,
- interner,
+ infcx,
};
- validator.validate_body(db);
+ validator.validate_body();
validator.diagnostics
}
}
@@ -98,11 +103,17 @@
env: Arc<TraitEnvironment<'db>>,
diagnostics: Vec<BodyValidationDiagnostic>,
validate_lints: bool,
- interner: DbInterner<'db>,
+ infcx: InferCtxt<'db>,
}
impl<'db> ExprValidator<'db> {
- fn validate_body(&mut self, db: &'db dyn HirDatabase) {
+ #[inline]
+ fn db(&self) -> &'db dyn HirDatabase {
+ self.infcx.interner.db
+ }
+
+ fn validate_body(&mut self) {
+ let db = self.db();
let mut filter_map_next_checker = None;
// we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
let body = Arc::clone(&self.body);
@@ -124,19 +135,19 @@
match expr {
Expr::Match { expr, arms } => {
- self.validate_match(id, *expr, arms, db);
+ self.validate_match(id, *expr, arms);
}
Expr::Call { .. } | Expr::MethodCall { .. } => {
- self.validate_call(db, id, expr, &mut filter_map_next_checker);
+ self.validate_call(id, expr, &mut filter_map_next_checker);
}
Expr::Closure { body: body_expr, .. } => {
self.check_for_trailing_return(*body_expr, &body);
}
Expr::If { .. } => {
- self.check_for_unnecessary_else(id, expr, db);
+ self.check_for_unnecessary_else(id, expr);
}
Expr::Block { .. } | Expr::Async { .. } | Expr::Unsafe { .. } => {
- self.validate_block(db, expr);
+ self.validate_block(expr);
}
_ => {}
}
@@ -157,10 +168,9 @@
fn validate_call(
&mut self,
- db: &dyn HirDatabase,
call_id: ExprId,
expr: &Expr,
- filter_map_next_checker: &mut Option<FilterMapNextChecker>,
+ filter_map_next_checker: &mut Option<FilterMapNextChecker<'db>>,
) {
if !self.validate_lints {
return;
@@ -176,8 +186,9 @@
None => return,
};
- let checker = filter_map_next_checker
- .get_or_insert_with(|| FilterMapNextChecker::new(&self.owner.resolver(db), db));
+ let checker = filter_map_next_checker.get_or_insert_with(|| {
+ FilterMapNextChecker::new(&self.owner.resolver(self.db()), self.db())
+ });
if checker.check(call_id, receiver, &callee).is_some() {
self.diagnostics.push(BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
@@ -186,27 +197,20 @@
}
if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) {
- checker.prev_receiver_ty = Some(receiver_ty.to_chalk(self.interner));
+ checker.prev_receiver_ty = Some(receiver_ty);
}
}
}
- fn validate_match(
- &mut self,
- match_expr: ExprId,
- scrutinee_expr: ExprId,
- arms: &[MatchArm],
- db: &dyn HirDatabase,
- ) {
+ fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: &[MatchArm]) {
let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else {
return;
};
- let scrut_ty = scrut_ty.to_chalk(self.interner);
- if scrut_ty.contains_unknown() {
+ if scrut_ty.references_non_lt_error() {
return;
}
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
let pattern_arena = Arena::new();
let mut m_arms = Vec::with_capacity(arms.len());
@@ -217,8 +221,7 @@
let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else {
return;
};
- let pat_ty = pat_ty.to_chalk(self.interner);
- if pat_ty.contains_unknown() {
+ if pat_ty.references_non_lt_error() {
return;
}
@@ -235,14 +238,14 @@
if (pat_ty == scrut_ty
|| scrut_ty
.as_reference()
- .map(|(match_expr_ty, ..)| *match_expr_ty == pat_ty)
+ .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
.unwrap_or(false))
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
{
// If we had a NotUsefulMatchArm diagnostic, we could
// check the usefulness of each pattern as we added it
// to the matrix here.
- let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
+ let pat = self.lower_pattern(&cx, arm.pat, &mut has_lowering_errors);
let m_arm = pat_analysis::MatchArm {
pat: pattern_arena.alloc(pat),
has_guard: arm.guard.is_some(),
@@ -258,15 +261,12 @@
return;
}
- let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr, db));
- let report = match cx.compute_match_usefulness(
- m_arms.as_slice(),
- scrut_ty.clone(),
- known_valid_scrutinee,
- ) {
- Ok(report) => report,
- Err(()) => return,
- };
+ let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr));
+ let report =
+ match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty, known_valid_scrutinee) {
+ Ok(report) => report,
+ Err(()) => return,
+ };
// FIXME Report unreachable arms
// https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
@@ -277,10 +277,10 @@
match_expr,
uncovered_patterns: missing_match_arms(
&cx,
- &scrut_ty,
+ scrut_ty,
witnesses,
m_arms.is_empty(),
- self.owner.krate(db),
+ self.owner.krate(self.db()),
),
});
}
@@ -291,7 +291,9 @@
// While the above function in rustc uses thir exprs, r-a doesn't have them.
// So, the logic here is getting same result as "hir lowering + match with lowered thir"
// with "hir only"
- fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool {
+ fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId) -> bool {
+ let db = self.db();
+
if self
.infer
.expr_adjustments
@@ -311,20 +313,18 @@
);
value_or_partial.is_none_or(|v| !matches!(v, ValueNs::StaticId(_)))
}
- Expr::Field { expr, .. } => {
- match self.infer.type_of_expr[*expr].to_chalk(self.interner).kind(Interner) {
- TyKind::Adt(adt, ..) if matches!(adt.0, AdtId::UnionId(_)) => false,
- _ => self.is_known_valid_scrutinee(*expr, db),
- }
- }
- Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db),
- Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db),
+ Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind() {
+ TyKind::Adt(adt, ..) if matches!(adt.def_id().0, AdtId::UnionId(_)) => false,
+ _ => self.is_known_valid_scrutinee(*expr),
+ },
+ Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base),
+ Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr),
Expr::Missing => false,
_ => true,
}
}
- fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
+ fn validate_block(&mut self, expr: &Expr) {
let (Expr::Block { statements, .. }
| Expr::Async { statements, .. }
| Expr::Unsafe { statements, .. }) = expr
@@ -332,7 +332,7 @@
return;
};
let pattern_arena = Arena::new();
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
for stmt in &**statements {
let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
continue;
@@ -342,13 +342,12 @@
}
let Some(initializer) = initializer else { continue };
let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue };
- let ty = ty.to_chalk(self.interner);
- if ty.contains_unknown() {
+ if ty.references_non_lt_error() {
continue;
}
let mut have_errors = false;
- let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
+ let deconstructed_pat = self.lower_pattern(&cx, pat, &mut have_errors);
// optimization, wildcard trivially hold
if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
@@ -360,7 +359,7 @@
has_guard: false,
arm_data: (),
};
- let report = match cx.compute_match_usefulness(&[match_arm], ty.clone(), None) {
+ let report = match cx.compute_match_usefulness(&[match_arm], ty, None) {
Ok(v) => v,
Err(e) => {
debug!(?e, "match usefulness error");
@@ -373,24 +372,23 @@
pat,
uncovered_patterns: missing_match_arms(
&cx,
- &ty,
+ ty,
witnesses,
false,
- self.owner.krate(db),
+ self.owner.krate(self.db()),
),
});
}
}
}
- fn lower_pattern<'p>(
+ fn lower_pattern<'a>(
&self,
- cx: &MatchCheckCtx<'p>,
+ cx: &MatchCheckCtx<'a, 'db>,
pat: PatId,
- db: &dyn HirDatabase,
have_errors: &mut bool,
- ) -> DeconstructedPat<'p> {
- let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body);
+ ) -> DeconstructedPat<'a, 'db> {
+ let mut patcx = match_check::PatCtxt::new(self.db(), &self.infer, &self.body);
let pattern = patcx.lower_pattern(pat);
let pattern = cx.lower_pat(&pattern);
if !patcx.errors.is_empty() {
@@ -434,7 +432,7 @@
}
}
- fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) {
+ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) {
if !self.validate_lints {
return;
}
@@ -453,11 +451,11 @@
&& last_then_expr_ty.is_never()
{
// Only look at sources if the then branch diverges and we have an else branch.
- let source_map = db.body_with_source_map(self.owner).1;
+ let source_map = self.db().body_with_source_map(self.owner).1;
let Ok(source_ptr) = source_map.expr_syntax(id) else {
return;
};
- let root = source_ptr.file_syntax(db);
+ let root = source_ptr.file_syntax(self.db());
let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root)
else {
return;
@@ -491,15 +489,15 @@
}
}
-struct FilterMapNextChecker {
+struct FilterMapNextChecker<'db> {
filter_map_function_id: Option<hir_def::FunctionId>,
next_function_id: Option<hir_def::FunctionId>,
prev_filter_map_expr_id: Option<ExprId>,
- prev_receiver_ty: Option<chalk_ir::Ty<Interner>>,
+ prev_receiver_ty: Option<Ty<'db>>,
}
-impl FilterMapNextChecker {
- fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
+impl<'db> FilterMapNextChecker<'db> {
+ fn new(resolver: &hir_def::resolver::Resolver<'db>, db: &'db dyn HirDatabase) -> Self {
// Find and store the FunctionIds for Iterator::filter_map and Iterator::next
let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
.resolve_function(db, resolver.krate())
@@ -639,15 +637,19 @@
!has_type_mismatches
}
-fn missing_match_arms<'p>(
- cx: &MatchCheckCtx<'p>,
- scrut_ty: &Ty,
- witnesses: Vec<WitnessPat<'p>>,
+fn missing_match_arms<'a, 'db>(
+ cx: &MatchCheckCtx<'a, 'db>,
+ scrut_ty: Ty<'a>,
+ witnesses: Vec<WitnessPat<'a, 'db>>,
arms_is_empty: bool,
krate: Crate,
) -> String {
- struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget);
- impl fmt::Display for DisplayWitness<'_, '_> {
+ struct DisplayWitness<'a, 'b, 'db>(
+ &'a WitnessPat<'b, 'db>,
+ &'a MatchCheckCtx<'b, 'db>,
+ DisplayTarget,
+ );
+ impl fmt::Display for DisplayWitness<'_, '_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let DisplayWitness(witness, cx, display_target) = *self;
let pat = cx.hoist_witness_pat(witness);
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index af541ff..80b65ac 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -9,7 +9,6 @@
pub(crate) mod pat_analysis;
-use chalk_ir::Mutability;
use hir_def::{
AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId,
expr_store::{Body, path::Path},
@@ -17,16 +16,16 @@
item_tree::FieldsShape,
};
use hir_expand::name::Name;
+use rustc_type_ir::inherent::{IntoKind, SliceLike};
use span::Edition;
-use stdx::{always, never};
+use stdx::{always, never, variance::PhantomCovariantLifetime};
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
- InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+ InferenceResult,
db::HirDatabase,
display::{HirDisplay, HirDisplayError, HirFormatter},
infer::BindingMode,
+ next_solver::{GenericArgs, Mutability, Ty, TyKind},
};
use self::pat_util::EnumerateAndAdjustIterator;
@@ -41,46 +40,46 @@
}
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct FieldPat {
+pub(crate) struct FieldPat<'db> {
pub(crate) field: LocalFieldId,
- pub(crate) pattern: Pat,
+ pub(crate) pattern: Pat<'db>,
}
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct Pat {
- pub(crate) ty: Ty,
- pub(crate) kind: Box<PatKind>,
+pub(crate) struct Pat<'db> {
+ pub(crate) ty: Ty<'db>,
+ pub(crate) kind: Box<PatKind<'db>>,
}
/// Close relative to `rustc_mir_build::thir::pattern::PatKind`
#[derive(Clone, Debug, PartialEq)]
-pub(crate) enum PatKind {
+pub(crate) enum PatKind<'db> {
Wild,
Never,
/// `x`, `ref x`, `x @ P`, etc.
Binding {
name: Name,
- subpattern: Option<Pat>,
+ subpattern: Option<Pat<'db>>,
},
/// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
/// multiple variants.
Variant {
- substs: Substitution,
+ substs: GenericArgs<'db>,
enum_variant: EnumVariantId,
- subpatterns: Vec<FieldPat>,
+ subpatterns: Vec<FieldPat<'db>>,
},
/// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
/// a single variant.
Leaf {
- subpatterns: Vec<FieldPat>,
+ subpatterns: Vec<FieldPat<'db>>,
},
/// `&P`, `&mut P`, etc.
Deref {
- subpattern: Pat,
+ subpattern: Pat<'db>,
},
// FIXME: for now, only bool literals are implemented
@@ -91,28 +90,27 @@
/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
- pats: Vec<Pat>,
+ pats: Vec<Pat<'db>>,
},
}
-pub(crate) struct PatCtxt<'db> {
+pub(crate) struct PatCtxt<'a, 'db> {
db: &'db dyn HirDatabase,
- infer: &'db InferenceResult<'db>,
- body: &'db Body,
+ infer: &'a InferenceResult<'db>,
+ body: &'a Body,
pub(crate) errors: Vec<PatternError>,
- interner: DbInterner<'db>,
}
-impl<'a> PatCtxt<'a> {
+impl<'a, 'db> PatCtxt<'a, 'db> {
pub(crate) fn new(
- db: &'a dyn HirDatabase,
- infer: &'a InferenceResult<'a>,
+ db: &'db dyn HirDatabase,
+ infer: &'a InferenceResult<'db>,
body: &'a Body,
) -> Self {
- Self { db, infer, body, errors: Vec::new(), interner: DbInterner::new_with(db, None, None) }
+ Self { db, infer, body, errors: Vec::new() }
}
- pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat {
+ pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat<'db> {
// XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
// When lowering of & and box patterns are implemented this should be tested
// in a manner of `match_ergonomics_issue_9095` test.
@@ -121,15 +119,12 @@
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
unadjusted_pat,
- |subpattern, ref_ty| Pat {
- ty: ref_ty.to_chalk(self.interner).clone(),
- kind: Box::new(PatKind::Deref { subpattern }),
- },
+ |subpattern, ref_ty| Pat { ty: *ref_ty, kind: Box::new(PatKind::Deref { subpattern }) },
)
}
- fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
- let mut ty = self.infer[pat].to_chalk(self.interner);
+ fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat<'db> {
+ let mut ty = self.infer[pat];
let variant = self.infer.variant_resolution_for_pat(pat);
let kind = match self.body[pat] {
@@ -142,8 +137,8 @@
}
hir_def::hir::Pat::Tuple { ref args, ellipsis } => {
- let arity = match *ty.kind(Interner) {
- TyKind::Tuple(arity, _) => arity,
+ let arity = match ty.kind() {
+ TyKind::Tuple(tys) => tys.len(),
_ => {
never!("unexpected type for tuple pattern: {:?}", ty);
self.errors.push(PatternError::UnexpectedType);
@@ -156,10 +151,10 @@
hir_def::hir::Pat::Bind { id, subpat, .. } => {
let bm = self.infer.binding_modes[pat];
- ty = self.infer[id].to_chalk(self.interner);
+ ty = self.infer[id];
let name = &self.body[id].name;
- match (bm, ty.kind(Interner)) {
- (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty.clone(),
+ match (bm, ty.kind()) {
+ (BindingMode::Ref(_), TyKind::Ref(_, rty, _)) => ty = rty,
(BindingMode::Ref(_), _) => {
never!(
"`ref {}` has wrong type {:?}",
@@ -167,7 +162,7 @@
ty
);
self.errors.push(PatternError::UnexpectedType);
- return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
+ return Pat { ty, kind: PatKind::Wild.into() };
}
_ => (),
}
@@ -177,7 +172,7 @@
hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
let expected_len = variant.unwrap().fields(self.db).fields().len();
let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
- self.lower_variant_or_leaf(pat, &ty, subpatterns)
+ self.lower_variant_or_leaf(pat, ty, subpatterns)
}
hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
@@ -193,7 +188,7 @@
})
.collect();
match subpatterns {
- Some(subpatterns) => self.lower_variant_or_leaf(pat, &ty, subpatterns),
+ Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
None => {
self.errors.push(PatternError::MissingField);
PatKind::Wild
@@ -213,7 +208,7 @@
}
};
- Pat { ty: ty.clone(), kind: Box::new(kind) }
+ Pat { ty, kind: Box::new(kind) }
}
fn lower_tuple_subpats(
@@ -221,7 +216,7 @@
pats: &[PatId],
expected_len: usize,
ellipsis: Option<u32>,
- ) -> Vec<FieldPat> {
+ ) -> Vec<FieldPat<'db>> {
if pats.len() > expected_len {
self.errors.push(PatternError::ExtraFields);
return Vec::new();
@@ -236,28 +231,28 @@
.collect()
}
- fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat> {
+ fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat<'db>> {
pats.iter().map(|&p| self.lower_pattern(p)).collect()
}
- fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat> {
+ fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat<'db>> {
pat.map(|p| self.lower_pattern(p))
}
fn lower_variant_or_leaf(
&mut self,
pat: PatId,
- ty: &Ty,
- subpatterns: Vec<FieldPat>,
- ) -> PatKind {
+ ty: Ty<'db>,
+ subpatterns: Vec<FieldPat<'db>>,
+ ) -> PatKind<'db> {
match self.infer.variant_resolution_for_pat(pat) {
Some(variant_id) => {
if let VariantId::EnumVariantId(enum_variant) = variant_id {
- let substs = match ty.kind(Interner) {
- TyKind::Adt(_, substs) => substs.clone(),
+ let substs = match ty.kind() {
+ TyKind::Adt(_, substs) => substs,
kind => {
always!(
- matches!(kind, TyKind::FnDef(..) | TyKind::Error),
+ matches!(kind, TyKind::FnDef(..) | TyKind::Error(_)),
"inappropriate type for def: {:?}",
ty
);
@@ -277,13 +272,13 @@
}
}
- fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat {
- let ty = self.infer[pat].to_chalk(self.interner);
+ fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat<'db> {
+ let ty = self.infer[pat];
- let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) };
+ let pat_from_kind = |kind| Pat { ty, kind: Box::new(kind) };
match self.infer.variant_resolution_for_pat(pat) {
- Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, &ty, Vec::new())),
+ Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())),
None => {
self.errors.push(PatternError::UnresolvedVariant);
pat_from_kind(PatKind::Wild)
@@ -291,7 +286,7 @@
}
}
- fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind {
+ fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind<'db> {
use hir_def::hir::{Expr, Literal::Bool};
match self.body[expr] {
@@ -304,8 +299,8 @@
}
}
-impl HirDisplay for Pat {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Pat<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match &*self.kind {
PatKind::Wild => write!(f, "_"),
PatKind::Never => write!(f, "!"),
@@ -361,7 +356,7 @@
.filter(|p| !matches!(*p.pattern.kind, PatKind::Wild))
.map(|p| {
printed += 1;
- WriteWith(|f| {
+ WriteWith::new(|f| {
write!(
f,
"{}: ",
@@ -387,7 +382,7 @@
if num_fields != 0 || variant.is_none() {
write!(f, "(")?;
let subpats = (0..num_fields).map(|i| {
- WriteWith(move |f| {
+ WriteWith::new(move |f| {
let fid = LocalFieldId::from_raw((i as u32).into());
if let Some(p) = subpatterns.get(i)
&& p.field == fid
@@ -402,7 +397,7 @@
})
});
f.write_joined(subpats, ", ")?;
- if let (TyKind::Tuple(..), 1) = (self.ty.kind(Interner), num_fields) {
+ if let (TyKind::Tuple(..), 1) = (self.ty.kind(), num_fields) {
write!(f, ",")?;
}
write!(f, ")")?;
@@ -411,8 +406,8 @@
Ok(())
}
PatKind::Deref { subpattern } => {
- match self.ty.kind(Interner) {
- &TyKind::Ref(mutbl, ..) => {
+ match self.ty.kind() {
+ TyKind::Ref(.., mutbl) => {
write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
}
_ => never!("{:?} is a bad Deref pattern type", self.ty),
@@ -425,15 +420,24 @@
}
}
-struct WriteWith<F>(F)
+struct WriteWith<'db, F>(F, PhantomCovariantLifetime<'db>)
where
- F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
+ F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
-impl<F> HirDisplay for WriteWith<F>
+impl<'db, F> WriteWith<'db, F>
where
- F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>,
+ F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
{
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+ fn new(f: F) -> Self {
+ Self(f, PhantomCovariantLifetime::new())
+ }
+}
+
+impl<'db, F> HirDisplay<'db> for WriteWith<'db, F>
+where
+ F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
+{
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
(self.0)(f)
}
}
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index eb20d3c..fb942e3 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -1,24 +1,27 @@
//! Interface with `rustc_pattern_analysis`.
-use std::cell::LazyCell;
-use std::fmt;
+use std::{cell::LazyCell, fmt};
-use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
+use hir_def::{EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
use intern::sym;
use rustc_pattern_analysis::{
IndexVec, PatCx, PrivateUninhabitedField,
constructor::{Constructor, ConstructorSet, VariantVisibility},
usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness},
};
+use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike};
use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
use crate::{
- AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind,
+ TraitEnvironment,
db::HirDatabase,
- infer::normalize,
inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
+ next_solver::{
+ Ty, TyKind,
+ infer::{InferCtxt, traits::ObligationCause},
+ },
};
use super::{FieldPat, Pat, PatKind};
@@ -26,10 +29,12 @@
use Constructor::*;
// Re-export r-a-specific versions of all these types.
-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>>;
+pub(crate) type DeconstructedPat<'a, 'db> =
+ rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'a, 'db>>;
+pub(crate) type MatchArm<'a, 'b, 'db> =
+ rustc_pattern_analysis::MatchArm<'b, MatchCheckCtx<'a, 'db>>;
+pub(crate) type WitnessPat<'a, 'db> =
+ rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'a, 'db>>;
/// [Constructor] uses this in unimplemented variants.
/// It allows porting match expressions from upstream algorithm without losing semantics.
@@ -65,37 +70,37 @@
}
#[derive(Clone)]
-pub(crate) struct MatchCheckCtx<'db> {
+pub(crate) struct MatchCheckCtx<'a, 'db> {
module: ModuleId,
- body: DefWithBodyId,
pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool,
env: Arc<TraitEnvironment<'db>>,
+ infcx: &'a InferCtxt<'db>,
}
-impl<'db> MatchCheckCtx<'db> {
+impl<'a, 'db> MatchCheckCtx<'a, 'db> {
pub(crate) fn new(
module: ModuleId,
- body: DefWithBodyId,
- db: &'db dyn HirDatabase,
+ infcx: &'a InferCtxt<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> Self {
+ let db = infcx.interner.db;
let def_map = module.crate_def_map(db);
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
- Self { module, body, db, exhaustive_patterns, env }
+ Self { module, db, exhaustive_patterns, env, infcx }
}
- pub(crate) fn compute_match_usefulness(
+ pub(crate) fn compute_match_usefulness<'b>(
&self,
- arms: &[MatchArm<'db>],
- scrut_ty: Ty,
+ arms: &[MatchArm<'a, 'b, 'db>],
+ scrut_ty: Ty<'db>,
known_valid_scrutinee: Option<bool>,
- ) -> Result<UsefulnessReport<'db, Self>, ()> {
- if scrut_ty.contains_unknown() {
+ ) -> Result<UsefulnessReport<'b, Self>, ()> {
+ if scrut_ty.references_non_lt_error() {
return Err(());
}
for arm in arms {
- if arm.pat.ty().contains_unknown() {
+ if arm.pat.ty().references_non_lt_error() {
return Err(());
}
}
@@ -106,8 +111,8 @@
compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
}
- fn is_uninhabited(&self, ty: &Ty) -> bool {
- is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone())
+ fn is_uninhabited(&self, ty: Ty<'db>) -> bool {
+ is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone())
}
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
@@ -140,23 +145,27 @@
// This lists the fields of a variant along with their types.
fn list_variant_fields(
&self,
- ty: &Ty,
+ ty: Ty<'db>,
variant: VariantId,
- ) -> impl Iterator<Item = (LocalFieldId, Ty)> {
+ ) -> impl Iterator<Item = (LocalFieldId, Ty<'db>)> {
let (_, substs) = ty.as_adt().unwrap();
let field_tys = self.db.field_types(variant);
let fields_len = variant.fields(self.db).fields().len() as u32;
(0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| {
- let ty = field_tys[fid].clone().substitute(Interner, substs);
- let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty);
+ let ty = field_tys[fid].instantiate(self.infcx.interner, substs);
+ let ty = self
+ .infcx
+ .at(&ObligationCause::dummy(), self.env.env)
+ .deeply_normalize(ty)
+ .unwrap_or(ty);
(fid, ty)
})
}
- pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> {
- let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)];
+ pub(crate) fn lower_pat(&self, pat: &Pat<'db>) -> DeconstructedPat<'a, 'db> {
+ let singleton = |pat: DeconstructedPat<'a, 'db>| vec![pat.at_index(0)];
let ctor;
let mut fields: Vec<_>;
let arity;
@@ -169,7 +178,7 @@
arity = 0;
}
PatKind::Deref { subpattern } => {
- ctor = match pat.ty.kind(Interner) {
+ ctor = match pat.ty.kind() {
TyKind::Ref(..) => Ref,
_ => {
never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
@@ -187,12 +196,13 @@
self.lower_pat(&pat.pattern).at_index(idx as usize)
})
.collect();
- match pat.ty.kind(Interner) {
- TyKind::Tuple(_, substs) => {
+ match pat.ty.kind() {
+ TyKind::Tuple(substs) => {
ctor = Struct;
- arity = substs.len(Interner);
+ arity = substs.len();
}
- &TyKind::Adt(AdtId(adt), _) => {
+ TyKind::Adt(adt_def, _) => {
+ let adt = adt_def.def_id().0;
ctor = match pat.kind.as_ref() {
PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => {
UnionField
@@ -240,15 +250,15 @@
arity = pats.len();
}
}
- DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ())
+ DeconstructedPat::new(ctor, fields, arity, pat.ty, ())
}
- pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat {
+ pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'a, 'db>) -> Pat<'db> {
let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p));
let kind = match pat.ctor() {
&Bool(value) => PatKind::LiteralBool { value },
IntRange(_) => unimplemented!(),
- Struct | Variant(_) | UnionField => match pat.ty().kind(Interner) {
+ Struct | Variant(_) | UnionField => match pat.ty().kind() {
TyKind::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.zip(0u32..)
@@ -259,15 +269,16 @@
.collect(),
},
TyKind::Adt(adt, substs) => {
- let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap();
+ let variant =
+ Self::variant_id_for_adt(self.db, pat.ctor(), adt.def_id().0).unwrap();
let subpatterns = self
- .list_variant_fields(pat.ty(), variant)
+ .list_variant_fields(*pat.ty(), variant)
.zip(subpatterns)
.map(|((field, _ty), pattern)| FieldPat { field, pattern })
.collect();
if let VariantId::EnumVariantId(enum_variant) = variant {
- PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns }
+ PatKind::Variant { substs, enum_variant, subpatterns }
} else {
PatKind::Leaf { subpatterns }
}
@@ -293,13 +304,13 @@
PatKind::Wild
}
};
- Pat { ty: pat.ty().clone(), kind: Box::new(kind) }
+ Pat { ty: *pat.ty(), kind: Box::new(kind) }
}
}
-impl PatCx for MatchCheckCtx<'_> {
+impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> {
type Error = ();
- type Ty = Ty;
+ type Ty = Ty<'db>;
type VariantIdx = EnumVariantContiguousIndex;
type StrLit = Void;
type ArmData = ();
@@ -315,10 +326,11 @@
ty: &Self::Ty,
) -> usize {
match ctor {
- Struct | Variant(_) | UnionField => match *ty.kind(Interner) {
- TyKind::Tuple(arity, ..) => arity,
- TyKind::Adt(AdtId(adt), ..) => {
- let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
+ Struct | Variant(_) | UnionField => match ty.kind() {
+ TyKind::Tuple(tys) => tys.len(),
+ TyKind::Adt(adt_def, ..) => {
+ let variant =
+ Self::variant_id_for_adt(self.db, ctor, adt_def.def_id().0).unwrap();
variant.fields(self.db).fields().len()
}
_ => {
@@ -346,24 +358,24 @@
) -> impl ExactSizeIterator<Item = (Self::Ty, PrivateUninhabitedField)> {
let single = |ty| smallvec![(ty, PrivateUninhabitedField(false))];
let tys: SmallVec<[_; 2]> = match ctor {
- Struct | Variant(_) | UnionField => match ty.kind(Interner) {
- TyKind::Tuple(_, substs) => {
- let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner));
- tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
+ Struct | Variant(_) | UnionField => match ty.kind() {
+ TyKind::Tuple(substs) => {
+ substs.iter().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
}
- TyKind::Ref(.., rty) => single(rty.clone()),
- &TyKind::Adt(AdtId(adt), ..) => {
+ TyKind::Ref(_, rty, _) => single(rty),
+ TyKind::Adt(adt_def, ..) => {
+ let adt = adt_def.def_id().0;
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
- self.list_variant_fields(ty, variant)
+ self.list_variant_fields(*ty, variant)
.map(move |(fid, ty)| {
let is_visible = || {
matches!(adt, hir_def::AdtId::EnumId(..))
|| visibilities[fid].is_visible_from(self.db, self.module)
};
- let is_uninhabited = self.is_uninhabited(&ty);
+ let is_uninhabited = self.is_uninhabited(ty);
let private_uninhabited = is_uninhabited && !is_visible();
(ty, PrivateUninhabitedField(private_uninhabited))
})
@@ -371,14 +383,14 @@
}
ty_kind => {
never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
- single(ty.clone())
+ single(*ty)
}
},
- Ref => match ty.kind(Interner) {
- TyKind::Ref(.., rty) => single(rty.clone()),
+ Ref => match ty.kind() {
+ TyKind::Ref(_, rty, _) => single(rty),
ty_kind => {
never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
- single(ty.clone())
+ single(*ty)
}
},
Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
@@ -414,42 +426,51 @@
// returned list of constructors.
// Invariant: this is empty if and only if the type is uninhabited (as determined by
// `cx.is_uninhabited()`).
- Ok(match ty.kind(Interner) {
- TyKind::Scalar(Scalar::Bool) => ConstructorSet::Bool,
- TyKind::Scalar(Scalar::Char) => unhandled(),
- TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
+ Ok(match ty.kind() {
+ TyKind::Bool => ConstructorSet::Bool,
+ TyKind::Char => unhandled(),
+ TyKind::Int(..) | TyKind::Uint(..) => unhandled(),
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
- &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
- let enum_data = enum_id.enum_variants(cx.db);
- let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
+ TyKind::Adt(adt_def, subst) => {
+ let adt = adt_def.def_id().0;
+ match adt {
+ hir_def::AdtId::EnumId(enum_id) => {
+ let enum_data = enum_id.enum_variants(cx.db);
+ let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
- if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
- ConstructorSet::NoConstructors
- } else {
- 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,
- self.env.clone(),
- );
- let visibility = if is_uninhabited {
- VariantVisibility::Empty
+ if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
+ ConstructorSet::NoConstructors
} else {
- VariantVisibility::Visible
- };
- variants.push(visibility);
- }
+ let mut variants = IndexVec::with_capacity(enum_data.variants.len());
+ for &(variant, _, _) in enum_data.variants.iter() {
+ let is_uninhabited = is_enum_variant_uninhabited_from(
+ cx.infcx,
+ variant,
+ subst,
+ cx.module,
+ self.env.clone(),
+ );
+ let visibility = if is_uninhabited {
+ VariantVisibility::Empty
+ } else {
+ VariantVisibility::Visible
+ };
+ variants.push(visibility);
+ }
- ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
+ ConstructorSet::Variants {
+ variants,
+ non_exhaustive: is_declared_nonexhaustive,
+ }
+ }
+ }
+ hir_def::AdtId::UnionId(_) => ConstructorSet::Union,
+ hir_def::AdtId::StructId(_) => {
+ ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) }
+ }
}
}
- TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union,
- TyKind::Adt(..) | TyKind::Tuple(..) => {
- ConstructorSet::Struct { empty: cx.is_uninhabited(ty) }
- }
+ TyKind::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) },
TyKind::Ref(..) => ConstructorSet::Ref,
TyKind::Never => ConstructorSet::NoConstructors,
// This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -492,14 +513,14 @@
fn report_mixed_deref_pat_ctors(
&self,
- _deref_pat: &DeconstructedPat<'_>,
- _normal_pat: &DeconstructedPat<'_>,
+ _deref_pat: &DeconstructedPat<'a, 'db>,
+ _normal_pat: &DeconstructedPat<'a, 'db>,
) {
// FIXME(deref_patterns): This could report an error comparable to the one in rustc.
}
}
-impl fmt::Debug for MatchCheckCtx<'_> {
+impl fmt::Debug for MatchCheckCtx<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish()
}
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 31100e1..53524d6 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -5,22 +5,21 @@
use either::Either;
use hir_def::{
- AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
+ AdtId, CallableDefId, DefWithBodyId, FieldId, FunctionId, VariantId,
expr_store::{Body, path::Path},
hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp},
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
signatures::StaticFlags,
type_ref::Rawness,
};
+use rustc_type_ir::inherent::IntoKind;
use span::Edition;
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
-use crate::utils::TargetFeatureIsSafeInTarget;
use crate::{
- InferenceResult, Interner, TargetFeatures, TyExt, TyKind,
+ InferenceResult, TargetFeatures,
db::HirDatabase,
- utils::{is_fn_unsafe_to_call, target_feature_is_safe_in_target},
+ next_solver::{CallableIdWrapper, TyKind, abi::Safety},
+ utils::{TargetFeatureIsSafeInTarget, is_fn_unsafe_to_call, target_feature_is_safe_in_target},
};
#[derive(Debug, Default)]
@@ -151,7 +150,6 @@
/// On some targets (WASM), calling safe functions with `#[target_feature]` is always safe, even when
/// the target feature is not enabled. This flag encodes that.
target_feature_is_safe: TargetFeatureIsSafeInTarget,
- interner: DbInterner<'db>,
}
impl<'db> UnsafeVisitor<'db> {
@@ -186,7 +184,6 @@
def_target_features,
edition,
target_feature_is_safe,
- interner: DbInterner::new_with(db, None, None),
}
}
@@ -289,12 +286,14 @@
let inside_assignment = mem::replace(&mut self.inside_assignment, false);
match expr {
&Expr::Call { callee, .. } => {
- let callee = self.infer[callee].to_chalk(self.interner);
- if let Some(func) = callee.as_fn_def(self.db) {
+ let callee = self.infer[callee];
+ if let TyKind::FnDef(CallableIdWrapper(CallableDefId::FunctionId(func)), _) =
+ callee.kind()
+ {
self.check_call(current, func);
}
- if let TyKind::Function(fn_ptr) = callee.kind(Interner)
- && fn_ptr.sig.safety == chalk_ir::Safety::Unsafe
+ if let TyKind::FnPtr(_, hdr) = callee.kind()
+ && hdr.safety == Safety::Unsafe
{
self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall);
}
@@ -342,7 +341,7 @@
}
}
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
- if let TyKind::Raw(..) = &self.infer[*expr].to_chalk(self.interner).kind(Interner) {
+ if let TyKind::RawPtr(..) = self.infer[*expr].kind() {
self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref);
}
}
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index bcd93c6..dd1b212 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -8,7 +8,6 @@
};
use base_db::Crate;
-use chalk_ir::{BoundVar, Safety, TyKind};
use either::Either;
use hir_def::{
FindPathConfig, GeneralConstId, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId,
@@ -36,39 +35,33 @@
Float,
ieee::{Half as f16, Quad as f128},
};
+use rustc_ast_ir::FloatTy;
use rustc_hash::FxHashSet;
use rustc_type_ir::{
- AliasTyKind, CoroutineArgsParts, RegionKind,
- inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike},
+ AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, CoroutineClosureArgsParts, RegionKind,
+ Upcast,
+ inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, Tys as _},
};
use smallvec::SmallVec;
use span::Edition;
use stdx::never;
use triomphe::Arc;
-use crate::next_solver::infer::traits::ObligationCause;
-use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk};
use crate::{
- AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar,
- ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
- LifetimeOutlives, MemoryMap, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
- TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval,
- db::{HirDatabase, InternedClosure},
- from_assoc_type_id, from_placeholder_idx,
+ CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval,
+ db::{HirDatabase, InternedClosure, InternedCoroutine},
generics::generics,
- infer::normalize,
layout::Layout,
- lt_from_placeholder_idx,
mir::pad16,
next_solver::{
- BoundExistentialPredicate, DbInterner, GenericArgs, SolverDefId,
- mapping::{
- ChalkToNextSolver, convert_args_for_result, convert_const_for_result,
- convert_region_for_result, convert_ty_for_result,
- },
+ AliasTy, Clause, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder,
+ ExistentialPredicate, FnSig, GenericArg, GenericArgs, PolyFnSig, Region, SolverDefId, Term,
+ TraitRef, Ty, TyKind, TypingMode,
+ abi::Safety,
+ infer::{DbInternerInferExt, traits::ObligationCause},
},
- primitive, to_assoc_type_id,
- utils::{self, ClosureSubst, detect_variant_from_bytes},
+ primitive,
+ utils::{self, detect_variant_from_bytes},
};
pub trait HirWrite: fmt::Write {
@@ -82,9 +75,10 @@
// `core::Formatter` will ignore metadata
impl HirWrite for fmt::Formatter<'_> {}
-pub struct HirFormatter<'a> {
+pub struct HirFormatter<'a, 'db> {
/// The database handle
- pub db: &'a dyn HirDatabase,
+ pub db: &'db dyn HirDatabase,
+ pub interner: DbInterner<'db>,
/// The sink to write into
fmt: &'a mut dyn HirWrite,
/// A buffer to intercept writes with, this allows us to track the overall size of the formatted output.
@@ -103,7 +97,7 @@
display_lifetimes: DisplayLifetime,
display_kind: DisplayKind,
display_target: DisplayTarget,
- bounds_formatting_ctx: BoundsFormattingCtx,
+ bounds_formatting_ctx: BoundsFormattingCtx<'db>,
}
// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
@@ -121,7 +115,7 @@
}
#[derive(Default)]
-enum BoundsFormattingCtx {
+enum BoundsFormattingCtx<'db> {
Entered {
/// We can have recursive bounds like the following case:
/// ```ignore
@@ -131,14 +125,14 @@
/// ```
/// So, record the projection types met while formatting bounds and
//. prevent recursing into their bounds to avoid infinite loops.
- projection_tys_met: FxHashSet<ProjectionTy>,
+ projection_tys_met: FxHashSet<AliasTy<'db>>,
},
#[default]
Exited,
}
-impl BoundsFormattingCtx {
- fn contains(&mut self, proj: &ProjectionTy) -> bool {
+impl<'db> BoundsFormattingCtx<'db> {
+ fn contains(&self, proj: &AliasTy<'db>) -> bool {
match self {
BoundsFormattingCtx::Entered { projection_tys_met } => {
projection_tys_met.contains(proj)
@@ -148,7 +142,7 @@
}
}
-impl HirFormatter<'_> {
+impl<'db> HirFormatter<'_, 'db> {
fn start_location_link(&mut self, location: ModuleDefId) {
self.fmt.start_location_link(location);
}
@@ -159,7 +153,7 @@
fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>(
&mut self,
- target: ProjectionTy,
+ target: AliasTy<'db>,
format_bounds: F,
) -> T {
match self.bounds_formatting_ctx {
@@ -181,52 +175,28 @@
}
}
- fn render_lifetime(&self, lifetime: &Lifetime) -> bool {
+ fn render_region(&self, lifetime: Region<'db>) -> bool {
match self.display_lifetimes {
DisplayLifetime::Always => true,
- DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static),
+ DisplayLifetime::OnlyStatic => matches!(lifetime.kind(), RegionKind::ReStatic),
DisplayLifetime::OnlyNamed => {
- matches!(***lifetime.interned(), LifetimeData::Placeholder(_))
+ matches!(lifetime.kind(), RegionKind::ReEarlyParam(_))
}
- DisplayLifetime::OnlyNamedOrStatic => matches!(
- ***lifetime.interned(),
- LifetimeData::Static | LifetimeData::Placeholder(_)
- ),
- DisplayLifetime::Never => false,
- }
- }
-
- fn render_region(&self, lifetime: crate::next_solver::Region<'_>) -> bool {
- match self.display_lifetimes {
- DisplayLifetime::Always => true,
- DisplayLifetime::OnlyStatic => {
- matches!(lifetime.kind(), rustc_type_ir::RegionKind::ReStatic)
+ DisplayLifetime::OnlyNamedOrStatic => {
+ matches!(lifetime.kind(), RegionKind::ReStatic | RegionKind::ReEarlyParam(_))
}
- DisplayLifetime::OnlyNamed => {
- matches!(
- lifetime.kind(),
- rustc_type_ir::RegionKind::RePlaceholder(_)
- | rustc_type_ir::RegionKind::ReEarlyParam(_)
- )
- }
- DisplayLifetime::OnlyNamedOrStatic => matches!(
- lifetime.kind(),
- rustc_type_ir::RegionKind::ReStatic
- | rustc_type_ir::RegionKind::RePlaceholder(_)
- | rustc_type_ir::RegionKind::ReEarlyParam(_)
- ),
DisplayLifetime::Never => false,
}
}
}
-pub trait HirDisplay {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
+pub trait HirDisplay<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
/// Returns a `Display`able type that is human-readable.
fn into_displayable<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
max_size: Option<usize>,
limited_size: Option<usize>,
omit_verbose_types: bool,
@@ -234,7 +204,7 @@
display_kind: DisplayKind,
closure_style: ClosureStyle,
show_container_bounds: bool,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -260,9 +230,9 @@
/// Use this for showing types to the user (e.g. diagnostics)
fn display<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
display_target: DisplayTarget,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -284,10 +254,10 @@
/// Use this for showing types to the user where space is constrained (e.g. doc popups)
fn display_truncated<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
max_size: Option<usize>,
display_target: DisplayTarget,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -309,10 +279,10 @@
/// Use this for showing definitions which may contain too many items, like `trait`, `struct`, `enum`
fn display_limited<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
limited_size: Option<usize>,
display_target: DisplayTarget,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -334,13 +304,16 @@
/// Use this when generating code (e.g. assists)
fn display_source_code<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
module_id: ModuleId,
allow_opaque: bool,
) -> Result<String, DisplaySourceCodeError> {
let mut result = String::new();
+ let interner =
+ DbInterner::new_with(db, Some(module_id.krate()), module_id.containing_block());
match self.hir_fmt(&mut HirFormatter {
db,
+ interner,
fmt: &mut result,
buf: String::with_capacity(20),
curr_size: 0,
@@ -364,9 +337,9 @@
/// Returns a String representation of `self` for test purposes
fn display_test<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
display_target: DisplayTarget,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -388,10 +361,10 @@
/// the container for functions
fn display_with_container_bounds<'a>(
&'a self,
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
show_container_bounds: bool,
display_target: DisplayTarget,
- ) -> HirDisplayWrapper<'a, Self>
+ ) -> HirDisplayWrapper<'a, 'db, Self>
where
Self: Sized,
{
@@ -410,7 +383,7 @@
}
}
-impl HirFormatter<'_> {
+impl<'db> HirFormatter<'_, 'db> {
pub fn krate(&self) -> Crate {
self.display_target.krate
}
@@ -419,7 +392,7 @@
self.display_target.edition
}
- pub fn write_joined<T: HirDisplay>(
+ pub fn write_joined<T: HirDisplay<'db>>(
&mut self,
iter: impl IntoIterator<Item = T>,
sep: &str,
@@ -536,8 +509,8 @@
}
}
-pub struct HirDisplayWrapper<'a, T> {
- db: &'a dyn HirDatabase,
+pub struct HirDisplayWrapper<'a, 'db, T> {
+ db: &'db dyn HirDatabase,
t: &'a T,
max_size: Option<usize>,
limited_size: Option<usize>,
@@ -564,10 +537,17 @@
Hide,
}
-impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
+impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
+ let krate = self.display_target.krate;
+ let block = match self.display_kind {
+ DisplayKind::SourceCode { target_module_id, .. } => target_module_id.containing_block(),
+ DisplayKind::Diagnostics | DisplayKind::Test => None,
+ };
+ let interner = DbInterner::new_with(self.db, Some(krate), block);
self.t.hir_fmt(&mut HirFormatter {
db: self.db,
+ interner,
fmt: f,
buf: String::with_capacity(self.max_size.unwrap_or(20)),
curr_size: 0,
@@ -594,9 +574,9 @@
}
}
-impl<T> fmt::Display for HirDisplayWrapper<'_, T>
+impl<'db, T> fmt::Display for HirDisplayWrapper<'_, 'db, T>
where
- T: HirDisplay,
+ T: HirDisplay<'db>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.write_to(f) {
@@ -614,196 +594,149 @@
const TYPE_HINT_TRUNCATION: &str = "…";
-impl<T: HirDisplay> HirDisplay for &T {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
HirDisplay::hir_fmt(*self, f)
}
}
-impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
HirDisplay::hir_fmt(self.as_ref(), f)
}
}
-impl HirDisplay for ProjectionTy {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- if f.should_truncate() {
- return write!(f, "{TYPE_HINT_TRUNCATION}");
- }
- let trait_ref = self.trait_ref(f.db);
- let self_ty = trait_ref.self_type_parameter(Interner);
+fn write_projection<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ alias: &AliasTy<'db>,
+) -> Result<(), HirDisplayError> {
+ if f.should_truncate() {
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
+ }
+ let trait_ref = alias.trait_ref(f.interner);
+ let self_ty = trait_ref.self_ty();
- // if we are projection on a type parameter, check if the projection target has bounds
- // itself, if so, we render them directly as `impl Bound` instead of the less useful
- // `<Param as Trait>::Assoc`
- if !f.display_kind.is_source_code()
- && let TyKind::Placeholder(idx) = self_ty.kind(Interner)
- && !f.bounds_formatting_ctx.contains(self)
- {
- let db = f.db;
- let id = from_placeholder_idx(db, *idx).0;
- let generics = generics(db, id.parent);
-
- let substs = generics.placeholder_subst(db);
- let bounds = db
- .generic_predicates(id.parent)
- .iter()
- .map(|pred| pred.clone().substitute(Interner, &substs))
+ // if we are projection on a type parameter, check if the projection target has bounds
+ // itself, if so, we render them directly as `impl Bound` instead of the less useful
+ // `<Param as Trait>::Assoc`
+ if !f.display_kind.is_source_code()
+ && let TyKind::Param(param) = self_ty.kind()
+ && !f.bounds_formatting_ctx.contains(alias)
+ {
+ // FIXME: We shouldn't use `param.id`, it should be removed. We should know the
+ // `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
+ let bounds =
+ f.db.generic_predicates(param.id.parent())
+ .instantiate_identity()
+ .into_iter()
+ .flatten()
.filter(|wc| {
- let ty = match wc.skip_binders() {
- WhereClause::Implemented(tr) => tr.self_type_parameter(Interner),
- WhereClause::TypeOutlives(t) => t.ty.clone(),
- // We shouldn't be here if these exist
- WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => {
- return false;
- }
+ let ty = match wc.kind().skip_binder() {
+ ClauseKind::Trait(tr) => tr.self_ty(),
+ ClauseKind::TypeOutlives(t) => t.0,
+ _ => return false,
};
- let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else {
+ let TyKind::Alias(AliasTyKind::Projection, a) = ty.kind() else {
return false;
};
- proj == self
+ a == *alias
})
.collect::<Vec<_>>();
- if !bounds.is_empty() {
- return f.format_bounds_with(self.clone(), |f| {
- write_bounds_like_dyn_trait_with_prefix(
- f,
- "impl",
- Either::Left(
- &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
- ),
- &bounds,
- SizedByDefault::NotSized,
- )
- });
- }
+ if !bounds.is_empty() {
+ return f.format_bounds_with(*alias, |f| {
+ write_bounds_like_dyn_trait_with_prefix(
+ f,
+ "impl",
+ Either::Left(Ty::new_alias(f.interner, AliasTyKind::Projection, *alias)),
+ &bounds,
+ SizedByDefault::NotSized,
+ )
+ });
}
-
- write!(f, "<")?;
- self_ty.hir_fmt(f)?;
- write!(f, " as ")?;
- trait_ref.hir_fmt(f)?;
- write!(
- f,
- ">::{}",
- f.db.type_alias_signature(from_assoc_type_id(self.associated_ty_id))
- .name
- .display(f.db, f.edition())
- )?;
- let proj_params =
- &self.substitution.as_slice(Interner)[trait_ref.substitution.len(Interner)..];
- hir_fmt_generics(f, proj_params, None, None)
}
+
+ write!(f, "<")?;
+ self_ty.hir_fmt(f)?;
+ write!(f, " as ")?;
+ trait_ref.hir_fmt(f)?;
+ write!(
+ f,
+ ">::{}",
+ f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition())
+ )?;
+ let proj_params = &alias.args.as_slice()[trait_ref.args.len()..];
+ hir_fmt_generics(f, proj_params, None, None)
}
-impl HirDisplay for OpaqueTy {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- if f.should_truncate() {
- return write!(f, "{TYPE_HINT_TRUNCATION}");
- }
-
- self.substitution.at(Interner, 0).hir_fmt(f)
- }
-}
-
-impl HirDisplay for GenericArg {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- match self.interned() {
- crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
- crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
- crate::GenericArgData::Const(c) => c.hir_fmt(f),
+impl<'db> HirDisplay<'db> for GenericArg<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ match self {
+ GenericArg::Ty(ty) => ty.hir_fmt(f),
+ GenericArg::Lifetime(lt) => lt.hir_fmt(f),
+ GenericArg::Const(c) => c.hir_fmt(f),
}
}
}
-impl<'db> HirDisplay for crate::next_solver::GenericArg<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Const<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.kind() {
- rustc_type_ir::GenericArgKind::Type(ty) => ty.hir_fmt(f),
- rustc_type_ir::GenericArgKind::Lifetime(lt) => lt.hir_fmt(f),
- rustc_type_ir::GenericArgKind::Const(c) => c.hir_fmt(f),
- }
- }
-}
-
-impl HirDisplay for Const {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- let c = self.to_nextsolver(DbInterner::new_with(f.db, None, None));
- c.hir_fmt(f)
- }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Const<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- match self.kind() {
- rustc_type_ir::ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
- rustc_type_ir::ConstKind::Bound(db, bound_const) => {
+ ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
+ ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => {
write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32())
}
- rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"),
- rustc_type_ir::ConstKind::Param(param) => {
+ ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
+ write!(f, "?c.{}", bound_const.var.as_u32())
+ }
+ ConstKind::Infer(..) => write!(f, "#c#"),
+ ConstKind::Param(param) => {
let generics = generics(f.db, param.id.parent());
let param_data = &generics[param.id.local_id()];
write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
Ok(())
}
- rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns(
+ ConstKind::Value(const_bytes) => render_const_scalar(
f,
&const_bytes.value.inner().memory,
&const_bytes.value.inner().memory_map,
const_bytes.ty,
),
- rustc_type_ir::ConstKind::Unevaluated(unev) => {
+ ConstKind::Unevaluated(unev) => {
let c = match unev.def {
SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
_ => unreachable!(),
};
write!(f, "{}", c.name(f.db))?;
- hir_fmt_generics_ns(f, unev.args.as_slice(), c.generic_def(f.db), None)?;
+ hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?;
Ok(())
}
- rustc_type_ir::ConstKind::Error(..) => f.write_char('_'),
- rustc_type_ir::ConstKind::Expr(..) => write!(f, "<const-expr>"),
+ ConstKind::Error(..) => f.write_char('_'),
+ ConstKind::Expr(..) => write!(f, "<const-expr>"),
}
}
}
-fn render_const_scalar(
- f: &mut HirFormatter<'_>,
+fn render_const_scalar<'db>(
+ f: &mut HirFormatter<'_, 'db>,
b: &[u8],
- memory_map: &MemoryMap<'_>,
- ty: &Ty,
+ memory_map: &MemoryMap<'db>,
+ ty: Ty<'db>,
) -> Result<(), HirDisplayError> {
let trait_env = TraitEnvironment::empty(f.krate());
- let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
- let ty = normalize(f.db, trait_env.clone(), ty.clone());
- let ty = ty.to_nextsolver(interner);
- render_const_scalar_inner(f, b, memory_map, ty, trait_env)
-}
-
-fn render_const_scalar_ns(
- f: &mut HirFormatter<'_>,
- b: &[u8],
- memory_map: &MemoryMap<'_>,
- ty: crate::next_solver::Ty<'_>,
-) -> Result<(), HirDisplayError> {
- let trait_env = TraitEnvironment::empty(f.krate());
- let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
- let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis);
+ let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty);
render_const_scalar_inner(f, b, memory_map, ty, trait_env)
}
fn render_const_scalar_inner<'db>(
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
b: &[u8],
- memory_map: &MemoryMap<'_>,
- ty: crate::next_solver::Ty<'db>,
+ memory_map: &MemoryMap<'db>,
+ ty: Ty<'db>,
trait_env: Arc<TraitEnvironment<'db>>,
) -> Result<(), HirDisplayError> {
- use rustc_type_ir::TyKind;
+ use TyKind;
match ty.kind() {
TyKind::Bool => write!(f, "{}", b[0] != 0),
TyKind::Char => {
@@ -822,7 +755,7 @@
write!(f, "{it}")
}
TyKind::Float(fl) => match fl {
- rustc_type_ir::FloatTy::F16 => {
+ 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();
@@ -833,15 +766,15 @@
write!(f, "{s}")
}
}
- rustc_type_ir::FloatTy::F32 => {
+ FloatTy::F32 => {
let it = f32::from_le_bytes(b.try_into().unwrap());
write!(f, "{it:?}")
}
- rustc_type_ir::FloatTy::F64 => {
+ FloatTy::F64 => {
let it = f64::from_le_bytes(b.try_into().unwrap());
write!(f, "{it:?}")
}
- rustc_type_ir::FloatTy::F128 => {
+ 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();
@@ -890,7 +823,7 @@
f.write_str(", ")?;
}
let offset = size_one * i;
- render_const_scalar_ns(f, &bytes[offset..offset + size_one], memory_map, ty)?;
+ render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
}
f.write_str("]")
}
@@ -908,7 +841,7 @@
return f.write_str("<ref-data-not-available>");
};
f.write_str("&")?;
- render_const_scalar_ns(f, bytes, memory_map, t)
+ render_const_scalar(f, bytes, memory_map, t)
}
TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id().0 {
hir_def::AdtId::StructId(s) => {
@@ -938,7 +871,7 @@
return f.write_str("<ref-data-not-available>");
};
f.write_str("&")?;
- render_const_scalar_ns(f, bytes, memory_map, t)
+ render_const_scalar(f, bytes, memory_map, t)
}
},
TyKind::Tuple(tys) => {
@@ -959,7 +892,7 @@
continue;
};
let size = layout.size.bytes_usize();
- render_const_scalar_ns(f, &b[offset..offset + size], memory_map, ty)?;
+ render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
}
f.write_str(")")
}
@@ -1041,7 +974,7 @@
f.write_str(", ")?;
}
let offset = size_one * i;
- render_const_scalar_ns(f, &b[offset..offset + size_one], memory_map, ty)?;
+ render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
}
f.write_str("]")
}
@@ -1067,28 +1000,24 @@
fn render_variant_after_name<'db>(
data: &VariantFields,
- f: &mut HirFormatter<'_>,
- field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
+ f: &mut HirFormatter<'_, 'db>,
+ field_types: &ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>,
trait_env: Arc<TraitEnvironment<'db>>,
layout: &Layout,
- args: GenericArgs<'_>,
+ args: GenericArgs<'db>,
b: &[u8],
- memory_map: &MemoryMap<'_>,
+ memory_map: &MemoryMap<'db>,
) -> Result<(), HirDisplayError> {
- let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
match data.shape {
FieldsShape::Record | FieldsShape::Tuple => {
- let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
+ let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| {
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
- let ty = field_types[id]
- .clone()
- .substitute(Interner, &convert_args_for_result(interner, args.as_slice()));
- let Ok(layout) = f.db.layout_of_ty(ty.to_nextsolver(interner), trait_env.clone())
- else {
+ let ty = field_types[id].instantiate(f.interner, args);
+ let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else {
return f.write_str("<layout-error>");
};
let size = layout.size.bytes_usize();
- render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
+ render_const_scalar(f, &b[offset..offset + size], memory_map, ty)
};
let mut it = data.fields().iter();
if matches!(data.shape, FieldsShape::Record) {
@@ -1120,41 +1049,25 @@
}
}
-impl HirDisplay for BoundVar {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- write!(f, "?{}.{}", self.debruijn.depth(), self.index)
- }
-}
-
-impl HirDisplay for Ty {
+impl<'db> HirDisplay<'db> for Ty<'db> {
fn hir_fmt(
&self,
- f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
+ f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
- let ty = self.to_nextsolver(DbInterner::new_with(db, None, None));
- ty.hir_fmt(f)
- }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Ty<'db> {
- fn hir_fmt(
- &self,
- f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
- ) -> Result<(), HirDisplayError> {
- let interner = DbInterner::new_with(db, None, None);
+ let interner = f.interner;
if f.should_truncate() {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}
- use rustc_type_ir::TyKind;
+ use TyKind;
match self.kind() {
TyKind::Never => write!(f, "!")?,
TyKind::Str => write!(f, "str")?,
TyKind::Bool => write!(f, "bool")?,
TyKind::Char => write!(f, "char")?,
- TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string_ns(t))?,
- TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string_ns(t))?,
- TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string_ns(t))?,
+ TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string(t))?,
+ TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string(t))?,
+ TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
TyKind::Slice(t) => {
write!(f, "[")?;
t.hir_fmt(f)?;
@@ -1164,14 +1077,14 @@
write!(f, "[")?;
t.hir_fmt(f)?;
write!(f, "; ")?;
- convert_const_for_result(interner, c).hir_fmt(f)?;
+ c.hir_fmt(f)?;
write!(f, "]")?;
}
kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => {
if let TyKind::Ref(l, _, _) = kind {
f.write_char('&')?;
if f.render_region(l) {
- convert_region_for_result(interner, l).hir_fmt(f)?;
+ l.hir_fmt(f)?;
f.write_char(' ')?;
}
match m {
@@ -1190,32 +1103,18 @@
}
// FIXME: all this just to decide whether to use parentheses...
- let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
- bounds.iter().any(|bound| {
- if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
- let trait_ = trait_ref.hir_trait_id();
- fn_traits(db, trait_).any(|it| it == trait_)
- } else {
- false
- }
- })
- };
- let contains_impl_fn_ns = |bounds: &[BoundExistentialPredicate<'_>]| {
- bounds.iter().any(|bound| match bound.skip_binder() {
- rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
- let trait_ = trait_ref.def_id.0;
- fn_traits(db, trait_).any(|it| it == trait_)
- }
- _ => false,
- })
- };
let (preds_to_print, has_impl_fn_pred) = match t.kind() {
TyKind::Dynamic(bounds, region) => {
+ let contains_impl_fn =
+ bounds.iter().any(|bound| match bound.skip_binder() {
+ ExistentialPredicate::Trait(trait_ref) => {
+ let trait_ = trait_ref.def_id.0;
+ fn_traits(db, trait_).any(|it| it == trait_)
+ }
+ _ => false,
+ });
let render_lifetime = f.render_region(region);
- (
- bounds.len() + render_lifetime as usize,
- contains_impl_fn_ns(bounds.as_slice()),
- )
+ (bounds.len() + render_lifetime as usize, contains_impl_fn)
}
TyKind::Alias(AliasTyKind::Opaque, ty) => {
let opaque_ty_id = match ty.def_id {
@@ -1227,26 +1126,23 @@
let datas = db
.return_type_impl_traits(func)
.expect("impl trait id without data");
- let data =
- (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
- let bounds = data.substitute(
- Interner,
- &convert_args_for_result(interner, ty.args.as_slice()),
- );
- let mut len = bounds.skip_binders().len();
+ let data = (*datas)
+ .as_ref()
+ .map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+ let bounds =
+ || data.iter_instantiated_copied(f.interner, ty.args.as_slice());
+ let mut len = bounds().count();
// Don't count Sized but count when it absent
// (i.e. when explicit ?Sized bound is set).
let default_sized = SizedByDefault::Sized { anchor: func.krate(db) };
- let sized_bounds = bounds
- .skip_binders()
- .iter()
+ let sized_bounds = bounds()
.filter(|b| {
matches!(
- b.skip_binders(),
- WhereClause::Implemented(trait_ref)
+ b.kind().skip_binder(),
+ ClauseKind::Trait(trait_ref)
if default_sized.is_sized_trait(
- trait_ref.hir_trait_id(),
+ trait_ref.def_id().0,
db,
),
)
@@ -1259,7 +1155,15 @@
}
}
- (len, contains_impl_fn(bounds.skip_binders()))
+ let contains_impl_fn = bounds().any(|bound| {
+ if let ClauseKind::Trait(trait_ref) = bound.kind().skip_binder() {
+ let trait_ = trait_ref.def_id().0;
+ fn_traits(db, trait_).any(|it| it == trait_)
+ } else {
+ false
+ }
+ });
+ (len, contains_impl_fn)
} else {
(0, false)
}
@@ -1291,31 +1195,28 @@
}
}
TyKind::FnPtr(sig, header) => {
- let sig = CallableSig::from_fn_sig_and_header(interner, sig, header);
+ let sig = sig.with(header);
sig.hir_fmt(f)?;
}
TyKind::FnDef(def, args) => {
let def = def.0;
- let sig = db
- .callable_item_signature(def)
- .instantiate(interner, args)
- .skip_binder()
- .to_chalk(interner);
+ let sig = db.callable_item_signature(def).instantiate(interner, args);
if f.display_kind.is_source_code() {
// `FnDef` is anonymous and there's no surface syntax for it. Show it as a
// function pointer type.
return sig.hir_fmt(f);
}
- if let Safety::Unsafe = sig.safety {
+ if let Safety::Unsafe = sig.safety() {
write!(f, "unsafe ")?;
}
- if !matches!(sig.abi, FnAbi::Rust | FnAbi::RustCall) {
+ if !matches!(sig.abi(), FnAbi::Rust | FnAbi::RustCall) {
f.write_str("extern \"")?;
- f.write_str(sig.abi.as_str())?;
+ f.write_str(sig.abi().as_str())?;
f.write_str("\" ")?;
}
+ let sig = sig.skip_binder();
write!(f, "fn ")?;
f.start_location_link(def.into());
match def {
@@ -1338,13 +1239,12 @@
};
f.end_location_link();
- let parameters = convert_args_for_result(interner, args.as_slice());
- if parameters.len(Interner) > 0 {
+ if args.len() > 0 {
let generic_def_id = GenericDefId::from_callable(db, def);
let generics = generics(db, generic_def_id);
let (parent_len, self_param, type_, const_, impl_, lifetime) =
generics.provenance_split();
- let parameters = parameters.as_slice(Interner);
+ let parameters = args.as_slice();
debug_assert_eq!(
parameters.len(),
parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
@@ -1389,9 +1289,9 @@
}
}
write!(f, "(")?;
- f.write_joined(sig.params(), ", ")?;
+ f.write_joined(sig.inputs(), ", ")?;
write!(f, ")")?;
- let ret = sig.ret();
+ let ret = sig.output();
if !ret.is_unit() {
write!(f, " -> ")?;
ret.hir_fmt(f)?;
@@ -1434,27 +1334,9 @@
}
f.end_location_link();
- hir_fmt_generics(
- f,
- convert_args_for_result(interner, parameters.as_slice()).as_slice(Interner),
- Some(def.def_id().0.into()),
- None,
- )?;
+ hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?;
}
- TyKind::Alias(AliasTyKind::Projection, alias_ty) => {
- let type_alias = match alias_ty.def_id {
- SolverDefId::TypeAliasId(id) => id,
- _ => unreachable!(),
- };
- let parameters = convert_args_for_result(interner, alias_ty.args.as_slice());
-
- let projection_ty = ProjectionTy {
- associated_ty_id: to_assoc_type_id(type_alias),
- substitution: parameters.clone(),
- };
-
- projection_ty.hir_fmt(f)?;
- }
+ TyKind::Alias(AliasTyKind::Projection, alias_ty) => write_projection(f, &alias_ty)?,
TyKind::Foreign(alias) => {
let type_alias = db.type_alias_signature(alias.0);
f.start_location_link(alias.0.into());
@@ -1466,7 +1348,6 @@
SolverDefId::InternedOpaqueTyId(id) => id,
_ => unreachable!(),
};
- let parameters = convert_args_for_result(interner, alias_ty.args.as_slice());
if !f.display_kind.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
@@ -1478,14 +1359,16 @@
let datas =
db.return_type_impl_traits(func).expect("impl trait id without data");
let data =
- (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
- let bounds = data.substitute(Interner, ¶meters);
+ (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+ let bounds = data
+ .iter_instantiated_copied(interner, alias_ty.args.as_slice())
+ .collect::<Vec<_>>();
let krate = func.krate(db);
write_bounds_like_dyn_trait_with_prefix(
f,
"impl",
- Either::Left(&convert_ty_for_result(interner, *self)),
- bounds.skip_binders(),
+ Either::Left(*self),
+ &bounds,
SizedByDefault::Sized { anchor: krate },
)?;
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
@@ -1493,20 +1376,254 @@
ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data");
- let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
- let bounds = data.substitute(Interner, ¶meters);
+ let data =
+ (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+ let bounds = data
+ .iter_instantiated_copied(interner, alias_ty.args.as_slice())
+ .collect::<Vec<_>>();
let krate = alias.krate(db);
write_bounds_like_dyn_trait_with_prefix(
f,
"impl",
- Either::Left(&convert_ty_for_result(interner, *self)),
- bounds.skip_binders(),
+ Either::Left(*self),
+ &bounds,
SizedByDefault::Sized { anchor: krate },
)?;
}
- ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
+ }
+ }
+ TyKind::Closure(id, substs) => {
+ let id = id.0;
+ if f.display_kind.is_source_code() {
+ if !f.display_kind.allows_opaque() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::OpaqueType,
+ ));
+ } else if f.closure_style != ClosureStyle::ImplFn {
+ never!("Only `impl Fn` is valid for displaying closures in source code");
+ }
+ }
+ match f.closure_style {
+ ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+ ClosureStyle::ClosureWithId => {
+ return write!(
+ f,
+ "{{closure#{:?}}}",
+ salsa::plumbing::AsId::as_id(&id).index()
+ );
+ }
+ ClosureStyle::ClosureWithSubst => {
+ write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
+ return hir_fmt_generics(f, substs.as_slice(), None, None);
+ }
+ _ => (),
+ }
+ let sig = substs
+ .split_closure_args_untupled()
+ .closure_sig_as_fn_ptr_ty
+ .callable_sig(interner);
+ if let Some(sig) = sig {
+ let sig = sig.skip_binder();
+ let InternedClosure(def, _) = db.lookup_intern_closure(id);
+ let infer = db.infer(def);
+ let (_, kind) = infer.closure_info(id);
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
+ if sig.inputs().is_empty() {
+ } else if f.should_truncate() {
+ write!(f, "{TYPE_HINT_TRUNCATION}")?;
+ } else {
+ f.write_joined(sig.inputs(), ", ")?;
+ };
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, ")")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
+ if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
+ write!(f, " -> ")?;
+ sig.output().hir_fmt(f)?;
+ }
+ } else {
+ write!(f, "{{closure}}")?;
+ }
+ }
+ TyKind::CoroutineClosure(id, args) => {
+ let id = id.0;
+ if f.display_kind.is_source_code() {
+ if !f.display_kind.allows_opaque() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::OpaqueType,
+ ));
+ } else if f.closure_style != ClosureStyle::ImplFn {
+ never!("Only `impl Fn` is valid for displaying closures in source code");
+ }
+ }
+ match f.closure_style {
+ ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+ ClosureStyle::ClosureWithId => {
+ return write!(
+ f,
+ "{{async closure#{:?}}}",
+ salsa::plumbing::AsId::as_id(&id).index()
+ );
+ }
+ ClosureStyle::ClosureWithSubst => {
+ write!(
+ f,
+ "{{async closure#{:?}}}",
+ salsa::plumbing::AsId::as_id(&id).index()
+ )?;
+ return hir_fmt_generics(f, args.as_slice(), None, None);
+ }
+ _ => (),
+ }
+ let CoroutineClosureArgsParts { closure_kind_ty, signature_parts_ty, .. } =
+ args.split_coroutine_closure_args();
+ let kind = closure_kind_ty.to_opt_closure_kind().unwrap();
+ let kind = match kind {
+ rustc_type_ir::ClosureKind::Fn => "AsyncFn",
+ rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut",
+ rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce",
+ };
+ let TyKind::FnPtr(coroutine_sig, _) = signature_parts_ty.kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let coroutine_sig = coroutine_sig.skip_binder();
+ let coroutine_inputs = coroutine_sig.inputs();
+ let TyKind::Tuple(coroutine_inputs) = coroutine_inputs.as_slice()[1].kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let TyKind::Tuple(coroutine_output) = coroutine_sig.output().kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let coroutine_output = coroutine_output.as_slice()[1];
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
+ ClosureStyle::RANotation => write!(f, "async |")?,
+ _ => unreachable!(),
+ }
+ if coroutine_inputs.is_empty() {
+ } else if f.should_truncate() {
+ write!(f, "{TYPE_HINT_TRUNCATION}")?;
+ } else {
+ f.write_joined(coroutine_inputs, ", ")?;
+ };
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, ")")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
+ if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
+ write!(f, " -> ")?;
+ coroutine_output.hir_fmt(f)?;
+ }
+ }
+ TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
+ TyKind::Param(param) => {
+ // FIXME: We should not access `param.id`, it should be removed, and we should know the
+ // parent from the formatted type.
+ let generics = generics(db, param.id.parent());
+ let param_data = &generics[param.id.local_id()];
+ match param_data {
+ TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+ TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
+ write!(
+ f,
+ "{}",
+ p.name
+ .clone()
+ .unwrap_or_else(Name::missing)
+ .display(f.db, f.edition())
+ )?
+ }
+ TypeParamProvenance::ArgumentImplTrait => {
+ let bounds = db
+ .generic_predicates(param.id.parent())
+ .instantiate_identity()
+ .into_iter()
+ .flatten()
+ .filter(|wc| match wc.kind().skip_binder() {
+ ClauseKind::Trait(tr) => tr.self_ty() == *self,
+ ClauseKind::Projection(proj) => proj.self_ty() == *self,
+ ClauseKind::TypeOutlives(to) => to.0 == *self,
+ _ => false,
+ })
+ .collect::<Vec<_>>();
+ let krate = param.id.parent().module(db).krate();
+ write_bounds_like_dyn_trait_with_prefix(
+ f,
+ "impl",
+ Either::Left(*self),
+ &bounds,
+ SizedByDefault::Sized { anchor: krate },
+ )?;
+ }
+ },
+ TypeOrConstParamData::ConstParamData(p) => {
+ write!(f, "{}", p.name.display(f.db, f.edition()))?;
+ }
+ }
+ }
+ TyKind::Bound(BoundVarIndexKind::Bound(debruijn), ty) => {
+ write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())?
+ }
+ TyKind::Bound(BoundVarIndexKind::Canonical, ty) => {
+ write!(f, "?c.{}", ty.var.as_usize())?
+ }
+ TyKind::Dynamic(bounds, region) => {
+ // We want to put auto traits after principal traits, regardless of their written order.
+ let mut bounds_to_display = SmallVec::<[_; 4]>::new();
+ let mut auto_trait_bounds = SmallVec::<[_; 4]>::new();
+ for bound in bounds.iter() {
+ let clause = bound.with_self_ty(interner, *self);
+ match bound.skip_binder() {
+ ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
+ bounds_to_display.push(clause);
+ }
+ ExistentialPredicate::AutoTrait(_) => auto_trait_bounds.push(clause),
+ }
+ }
+ bounds_to_display.append(&mut auto_trait_bounds);
+
+ if f.render_region(region) {
+ bounds_to_display
+ .push(rustc_type_ir::OutlivesPredicate(*self, region).upcast(interner));
+ }
+
+ write_bounds_like_dyn_trait_with_prefix(
+ f,
+ "dyn",
+ Either::Left(*self),
+ &bounds_to_display,
+ SizedByDefault::NotSized,
+ )?;
+ }
+ TyKind::Error(_) => {
+ if f.display_kind.is_source_code() {
+ f.write_char('_')?;
+ } else {
+ write!(f, "{{unknown}}")?;
+ }
+ }
+ TyKind::Infer(..) => write!(f, "_")?,
+ TyKind::Coroutine(coroutine_id, subst) => {
+ let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db);
+ let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
+ subst.split_coroutine_args();
+ let body = db.body(owner);
+ let expr = &body[expr_id];
+ match expr {
+ hir_def::hir::Expr::Closure {
+ closure_kind: hir_def::hir::ClosureKind::Async,
+ ..
+ }
+ | hir_def::hir::Expr::Async { .. } => {
let future_trait =
- LangItem::Future.resolve_trait(db, body.module(db).krate());
+ LangItem::Future.resolve_trait(db, owner.module(db).krate());
let output = future_trait.and_then(|t| {
t.trait_items(db)
.associated_type_by_name(&Name::new_symbol_root(sym::Output))
@@ -1528,205 +1645,45 @@
f.end_location_link();
}
write!(f, " = ")?;
- parameters.at(Interner, 0).hir_fmt(f)?;
+ return_ty.hir_fmt(f)?;
write!(f, ">")?;
}
- }
- }
- TyKind::Closure(id, substs) => {
- let id = id.0;
- let substs = convert_args_for_result(interner, substs.as_slice());
- if f.display_kind.is_source_code() {
- if !f.display_kind.allows_opaque() {
- return Err(HirDisplayError::DisplaySourceCodeError(
- DisplaySourceCodeError::OpaqueType,
- ));
- } else if f.closure_style != ClosureStyle::ImplFn {
- never!("Only `impl Fn` is valid for displaying closures in source code");
- }
- }
- match f.closure_style {
- ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
- ClosureStyle::ClosureWithId => {
- return write!(
- f,
- "{{closure#{:?}}}",
- salsa::plumbing::AsId::as_id(&id).index()
- );
- }
- ClosureStyle::ClosureWithSubst => {
- write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
- return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
- }
- _ => (),
- }
- let sig = ClosureSubst(&substs).sig_ty(db).callable_sig(db);
- if let Some(sig) = sig {
- let InternedClosure(def, _) = db.lookup_intern_closure(id);
- let infer = db.infer(def);
- let (_, kind) = infer.closure_info(id);
- match f.closure_style {
- ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
- ClosureStyle::RANotation => write!(f, "|")?,
- _ => unreachable!(),
- }
- if sig.params().is_empty() {
- } else if f.should_truncate() {
- write!(f, "{TYPE_HINT_TRUNCATION}")?;
- } else {
- f.write_joined(sig.params(), ", ")?;
- };
- match f.closure_style {
- ClosureStyle::ImplFn => write!(f, ")")?,
- ClosureStyle::RANotation => write!(f, "|")?,
- _ => unreachable!(),
- }
- if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
+ hir_def::hir::Expr::Closure {
+ closure_kind: hir_def::hir::ClosureKind::Coroutine(..),
+ ..
+ } => {
+ if f.display_kind.is_source_code() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::Coroutine,
+ ));
+ }
+ write!(f, "|")?;
+ resume_ty.hir_fmt(f)?;
+ write!(f, "|")?;
+
+ write!(f, " yields ")?;
+ yield_ty.hir_fmt(f)?;
+
write!(f, " -> ")?;
- // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because
- // we don't have a trait environment here, required to normalize `<Ret as Future>::Output`.
- sig.ret().hir_fmt(f)?;
+ return_ty.hir_fmt(f)?;
}
- } else {
- write!(f, "{{closure}}")?;
+ _ => panic!("invalid expr for coroutine: {expr:?}"),
}
}
- TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
- TyKind::Param(param) => {
- let generics = generics(db, param.id.parent());
- let param_data = &generics[param.id.local_id()];
- match param_data {
- TypeOrConstParamData::TypeParamData(p) => match p.provenance {
- TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
- write!(
- f,
- "{}",
- p.name
- .clone()
- .unwrap_or_else(Name::missing)
- .display(f.db, f.edition())
- )?
- }
- TypeParamProvenance::ArgumentImplTrait => {
- let substs = generics.placeholder_subst(db);
- let bounds = db
- .generic_predicates(param.id.parent())
- .iter()
- .map(|pred| pred.clone().substitute(Interner, &substs))
- .filter(|wc| match wc.skip_binders() {
- WhereClause::Implemented(tr) => {
- tr.self_type_parameter(Interner)
- == convert_ty_for_result(interner, *self)
- }
- WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(proj),
- ty: _,
- }) => {
- proj.self_type_parameter(db)
- == convert_ty_for_result(interner, *self)
- }
- WhereClause::AliasEq(_) => false,
- WhereClause::TypeOutlives(to) => {
- to.ty == convert_ty_for_result(interner, *self)
- }
- WhereClause::LifetimeOutlives(_) => false,
- })
- .collect::<Vec<_>>();
- let krate = param.id.parent().module(db).krate();
- write_bounds_like_dyn_trait_with_prefix(
- f,
- "impl",
- Either::Left(&convert_ty_for_result(interner, *self)),
- &bounds,
- SizedByDefault::Sized { anchor: krate },
- )?;
- }
- },
- TypeOrConstParamData::ConstParamData(p) => {
- write!(f, "{}", p.name.display(f.db, f.edition()))?;
- }
- }
- }
- TyKind::Bound(debruijn_index, ty) => {
- let idx = chalk_ir::BoundVar {
- debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
- index: ty.var.as_usize(),
- };
- idx.hir_fmt(f)?
- }
- TyKind::Dynamic(..) => {
- let ty = convert_ty_for_result(interner, *self);
- let chalk_ir::TyKind::Dyn(dyn_ty) = ty.kind(Interner) else { unreachable!() };
- // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
- // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it
- // more efficient when either of them hits stable.
- let mut bounds: SmallVec<[_; 4]> =
- dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
- let (auto_traits, others): (SmallVec<[_; 4]>, _) =
- bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
- bounds.extend(others);
- bounds.extend(auto_traits);
-
- if f.render_lifetime(&dyn_ty.lifetime) {
- // we skip the binders in `write_bounds_like_dyn_trait_with_prefix`
- bounds.push(Binders::empty(
- Interner,
- chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
- ty: ty.clone(),
- lifetime: dyn_ty.lifetime.clone(),
- }),
- ));
- }
-
- write_bounds_like_dyn_trait_with_prefix(
- f,
- "dyn",
- Either::Left(&ty),
- &bounds,
- SizedByDefault::NotSized,
- )?;
- }
- TyKind::Error(_) => {
- if f.display_kind.is_source_code() {
- f.write_char('_')?;
- } else {
- write!(f, "{{unknown}}")?;
- }
- }
- TyKind::Infer(..) => write!(f, "_")?,
- TyKind::Coroutine(_, subst) => {
- if f.display_kind.is_source_code() {
- return Err(HirDisplayError::DisplaySourceCodeError(
- DisplaySourceCodeError::Coroutine,
- ));
- }
- let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
- subst.split_coroutine_args();
- write!(f, "|")?;
- resume_ty.hir_fmt(f)?;
- write!(f, "|")?;
-
- write!(f, " yields ")?;
- yield_ty.hir_fmt(f)?;
-
- write!(f, " -> ")?;
- return_ty.hir_fmt(f)?;
- }
TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
- TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?,
TyKind::Alias(_, _) => write!(f, "{{alias}}")?,
}
Ok(())
}
}
-fn hir_fmt_generics(
- f: &mut HirFormatter<'_>,
- parameters: &[GenericArg],
+fn hir_fmt_generics<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ parameters: &[GenericArg<'db>],
generic_def: Option<hir_def::GenericDefId>,
- self_: Option<&Ty>,
+ self_: Option<Ty<'db>>,
) -> Result<(), HirDisplayError> {
if parameters.is_empty() {
return Ok(());
@@ -1743,70 +1700,23 @@
Ok(())
}
-fn hir_fmt_generics_ns<'db>(
- f: &mut HirFormatter<'_>,
- parameters: &[crate::next_solver::GenericArg<'db>],
+fn generic_args_sans_defaults<'ga, 'db>(
+ f: &mut HirFormatter<'_, 'db>,
generic_def: Option<hir_def::GenericDefId>,
- self_: Option<crate::next_solver::Ty<'db>>,
-) -> Result<(), HirDisplayError> {
- if parameters.is_empty() {
- return Ok(());
- }
-
- let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters);
-
- if !parameters_to_write.is_empty() {
- write!(f, "<")?;
- hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?;
- write!(f, ">")?;
- }
-
- Ok(())
-}
-
-fn generic_args_sans_defaults<'ga>(
- f: &mut HirFormatter<'_>,
- generic_def: Option<hir_def::GenericDefId>,
- parameters: &'ga [GenericArg],
-) -> &'ga [GenericArg] {
+ parameters: &'ga [GenericArg<'db>],
+) -> &'ga [GenericArg<'db>] {
if f.display_kind.is_source_code() || f.omit_verbose_types() {
- match generic_def
- .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
- .filter(|it| !it.is_empty())
- {
+ match generic_def.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) {
None => parameters,
Some(default_parameters) => {
- let should_show = |arg: &GenericArg, i: usize| {
- let is_err = |arg: &GenericArg| match arg.data(Interner) {
- chalk_ir::GenericArgData::Lifetime(it) => {
- *it.data(Interner) == LifetimeData::Error
- }
- chalk_ir::GenericArgData::Ty(it) => *it.kind(Interner) == TyKind::Error,
- chalk_ir::GenericArgData::Const(it) => matches!(
- it.data(Interner).value,
- ConstValue::Concrete(ConcreteConst {
- interned: ConstScalar::Unknown,
- ..
- })
- ),
- };
- // if the arg is error like, render it to inform the user
- if is_err(arg) {
- return true;
- }
- // otherwise, if the arg is equal to the param default, hide it (unless the
- // default is an error which can happen for the trait Self type)
- match default_parameters.get(i) {
- None => true,
- Some(default_parameter) => {
- // !is_err(default_parameter.skip_binders())
- // &&
- arg != &default_parameter.clone().substitute(Interner, ¶meters[..i])
- }
+ let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) {
+ None => true,
+ Some(default_parameter) => {
+ arg != default_parameter.instantiate(f.interner, ¶meters[..i])
}
};
let mut default_from = 0;
- for (i, parameter) in parameters.iter().enumerate() {
+ for (i, ¶meter) in parameters.iter().enumerate() {
if should_show(parameter, i) {
default_from = i + 1;
}
@@ -1820,114 +1730,30 @@
}
fn hir_fmt_generic_args<'db>(
- f: &mut HirFormatter<'_>,
- parameters: &[crate::next_solver::GenericArg<'db>],
+ f: &mut HirFormatter<'_, 'db>,
+ parameters: &[GenericArg<'db>],
generic_def: Option<hir_def::GenericDefId>,
- self_: Option<crate::next_solver::Ty<'db>>,
+ self_: Option<Ty<'db>>,
) -> Result<(), HirDisplayError> {
if parameters.is_empty() {
return Ok(());
}
- let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters);
+ let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
if !parameters_to_write.is_empty() {
write!(f, "<")?;
- hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?;
+ hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
write!(f, ">")?;
}
Ok(())
}
-fn generic_args_sans_defaults_ns<'ga, 'db>(
- f: &mut HirFormatter<'_>,
- generic_def: Option<hir_def::GenericDefId>,
- parameters: &'ga [crate::next_solver::GenericArg<'db>],
-) -> &'ga [crate::next_solver::GenericArg<'db>] {
- let interner = DbInterner::new_with(f.db, Some(f.krate()), None);
- if f.display_kind.is_source_code() || f.omit_verbose_types() {
- match generic_def
- .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
- .filter(|it| !it.is_empty())
- {
- None => parameters,
- Some(default_parameters) => {
- let should_show = |arg: &crate::next_solver::GenericArg<'db>, i: usize| {
- let is_err = |arg: &crate::next_solver::GenericArg<'db>| match arg.kind() {
- rustc_type_ir::GenericArgKind::Lifetime(it) => {
- matches!(it.kind(), RegionKind::ReError(..))
- }
- rustc_type_ir::GenericArgKind::Type(it) => {
- matches!(it.kind(), rustc_type_ir::TyKind::Error(..))
- }
- rustc_type_ir::GenericArgKind::Const(it) => {
- matches!(it.kind(), rustc_type_ir::ConstKind::Error(..),)
- }
- };
- // if the arg is error like, render it to inform the user
- if is_err(arg) {
- return true;
- }
- // otherwise, if the arg is equal to the param default, hide it (unless the
- // default is an error which can happen for the trait Self type)
- match default_parameters.get(i) {
- None => true,
- Some(default_parameter) => {
- // !is_err(default_parameter.skip_binders())
- // &&
- arg != &default_parameter
- .clone()
- .substitute(
- Interner,
- &convert_args_for_result(interner, ¶meters[..i]),
- )
- .to_nextsolver(interner)
- }
- }
- };
- let mut default_from = 0;
- for (i, parameter) in parameters.iter().enumerate() {
- if should_show(parameter, i) {
- default_from = i + 1;
- }
- }
- ¶meters[0..default_from]
- }
- }
- } else {
- parameters
- }
-}
-
-fn hir_fmt_generic_arguments(
- f: &mut HirFormatter<'_>,
- parameters: &[GenericArg],
- self_: Option<&Ty>,
-) -> Result<(), HirDisplayError> {
- let mut first = true;
- let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
-
- let (ty_or_const, lifetimes) = match lifetime_offset {
- Some(offset) => parameters.split_at(offset),
- None => (parameters, &[][..]),
- };
- for generic_arg in lifetimes.iter().chain(ty_or_const) {
- if !mem::take(&mut first) {
- write!(f, ", ")?;
- }
- match self_ {
- self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
- _ => generic_arg.hir_fmt(f)?,
- }
- }
- Ok(())
-}
-
-fn hir_fmt_generic_arguments_ns<'db>(
- f: &mut HirFormatter<'_>,
- parameters: &[crate::next_solver::GenericArg<'db>],
- self_: Option<crate::next_solver::Ty<'db>>,
+fn hir_fmt_generic_arguments<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ parameters: &[GenericArg<'db>],
+ self_: Option<Ty<'db>>,
) -> Result<(), HirDisplayError> {
let mut first = true;
let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some());
@@ -1948,9 +1774,28 @@
Ok(())
}
-impl HirDisplay for CallableSig {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- let CallableSig { params_and_return: _, is_varargs, safety, abi: _ } = *self;
+fn hir_fmt_tys<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ tys: &[Ty<'db>],
+ self_: Option<Ty<'db>>,
+) -> Result<(), HirDisplayError> {
+ let mut first = true;
+
+ for ty in tys {
+ if !mem::take(&mut first) {
+ write!(f, ", ")?;
+ }
+ match self_ {
+ Some(self_) if *ty == self_ => write!(f, "Self")?,
+ _ => ty.hir_fmt(f)?,
+ }
+ }
+ Ok(())
+}
+
+impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder();
if let Safety::Unsafe = safety {
write!(f, "unsafe ")?;
}
@@ -1961,16 +1806,16 @@
// f.write_str("\" ")?;
// }
write!(f, "fn(")?;
- f.write_joined(self.params(), ", ")?;
- if is_varargs {
- if self.params().is_empty() {
+ f.write_joined(inputs_and_output.inputs(), ", ")?;
+ if c_variadic {
+ if inputs_and_output.inputs().is_empty() {
write!(f, "...")?;
} else {
write!(f, ", ...")?;
}
}
write!(f, ")")?;
- let ret = self.ret();
+ let ret = inputs_and_output.output();
if !ret.is_unit() {
write!(f, " -> ")?;
ret.hir_fmt(f)?;
@@ -1979,6 +1824,15 @@
}
}
+impl<'db> HirDisplay<'db> for Term<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ match self {
+ Term::Ty(it) => it.hir_fmt(f),
+ Term::Const(it) => it.hir_fmt(f),
+ }
+ }
+}
+
fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
let krate = trait_.lookup(db).container.krate();
utils::fn_traits(db, krate)
@@ -2002,11 +1856,11 @@
}
}
-pub fn write_bounds_like_dyn_trait_with_prefix(
- f: &mut HirFormatter<'_>,
+pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
+ f: &mut HirFormatter<'_, 'db>,
prefix: &str,
- this: Either<&Ty, &Lifetime>,
- predicates: &[QuantifiedWhereClause],
+ this: Either<Ty<'db>, Region<'db>>,
+ predicates: &[Clause<'db>],
default_sized: SizedByDefault,
) -> Result<(), HirDisplayError> {
write!(f, "{prefix}")?;
@@ -2020,10 +1874,10 @@
}
}
-fn write_bounds_like_dyn_trait(
- f: &mut HirFormatter<'_>,
- this: Either<&Ty, &Lifetime>,
- predicates: &[QuantifiedWhereClause],
+fn write_bounds_like_dyn_trait<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ this: Either<Ty<'db>, Region<'db>>,
+ predicates: &[Clause<'db>],
default_sized: SizedByDefault,
) -> Result<(), HirDisplayError> {
// Note: This code is written to produce nice results (i.e.
@@ -2036,10 +1890,10 @@
let mut angle_open = false;
let mut is_fn_trait = false;
let mut is_sized = false;
- for p in predicates.iter() {
- match p.skip_binders() {
- WhereClause::Implemented(trait_ref) => {
- let trait_ = trait_ref.hir_trait_id();
+ for p in predicates {
+ match p.kind().skip_binder() {
+ ClauseKind::Trait(trait_ref) => {
+ let trait_ = trait_ref.def_id().0;
if default_sized.is_sized_trait(trait_, f.db) {
is_sized = true;
if matches!(default_sized, SizedByDefault::Sized { .. }) {
@@ -2064,31 +1918,30 @@
write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
f.end_location_link();
if is_fn_trait {
- if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner)
- && let Some(args) =
- params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
+ if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice()
+ && let Some(args) = params.first().and_then(|it| it.ty()?.as_tuple())
{
write!(f, "(")?;
- hir_fmt_generic_arguments(f, args.as_slice(Interner), self_.ty(Interner))?;
+ hir_fmt_tys(f, args.as_slice(), Some(trait_ref.trait_ref.self_ty()))?;
write!(f, ")")?;
}
} else {
let params = generic_args_sans_defaults(
f,
Some(trait_.into()),
- trait_ref.substitution.as_slice(Interner),
+ trait_ref.trait_ref.args.as_slice(),
);
- if let [self_, params @ ..] = params
+ if let [_self, params @ ..] = params
&& !params.is_empty()
{
write!(f, "<")?;
- hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
+ hir_fmt_generic_arguments(f, params, Some(trait_ref.trait_ref.self_ty()))?;
// there might be assoc type bindings, so we leave the angle brackets open
angle_open = true;
}
}
}
- WhereClause::TypeOutlives(to) if Either::Left(&to.ty) == this => {
+ ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => {
if !is_fn_trait && angle_open {
write!(f, ">")?;
angle_open = false;
@@ -2096,10 +1949,9 @@
if !first {
write!(f, " + ")?;
}
- to.lifetime.hir_fmt(f)?;
+ to.1.hir_fmt(f)?;
}
- WhereClause::TypeOutlives(_) => {}
- WhereClause::LifetimeOutlives(lo) if Either::Right(&lo.a) == this => {
+ ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => {
if !is_fn_trait && angle_open {
write!(f, ">")?;
angle_open = false;
@@ -2107,17 +1959,16 @@
if !first {
write!(f, " + ")?;
}
- lo.b.hir_fmt(f)?;
+ lo.1.hir_fmt(f)?;
}
- WhereClause::LifetimeOutlives(_) => {}
- WhereClause::AliasEq(alias_eq) if is_fn_trait => {
+ ClauseKind::Projection(projection) if is_fn_trait => {
is_fn_trait = false;
- if !alias_eq.ty.is_unit() {
+ if !projection.term.as_type().is_some_and(|it| it.is_unit()) {
write!(f, " -> ")?;
- alias_eq.ty.hir_fmt(f)?;
+ projection.term.hir_fmt(f)?;
}
}
- WhereClause::AliasEq(AliasEq { ty, alias }) => {
+ ClauseKind::Projection(projection) => {
// in types in actual Rust, these will always come
// after the corresponding Implemented predicate
if angle_open {
@@ -2126,28 +1977,22 @@
write!(f, "<")?;
angle_open = true;
}
- if let AliasTy::Projection(proj) = alias {
- let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
- let type_alias = f.db.type_alias_signature(assoc_ty_id);
- f.start_location_link(assoc_ty_id.into());
- write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
- f.end_location_link();
+ let assoc_ty_id = projection.def_id().expect_type_alias();
+ let type_alias = f.db.type_alias_signature(assoc_ty_id);
+ f.start_location_link(assoc_ty_id.into());
+ write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
+ f.end_location_link();
- let proj_arg_count = generics(f.db, assoc_ty_id.into()).len_self();
- let parent_len = proj.substitution.len(Interner) - proj_arg_count;
- if proj_arg_count > 0 {
- write!(f, "<")?;
- hir_fmt_generic_arguments(
- f,
- &proj.substitution.as_slice(Interner)[parent_len..],
- None,
- )?;
- write!(f, ">")?;
- }
- write!(f, " = ")?;
+ let own_args = projection.projection_term.own_args(f.interner);
+ if !own_args.is_empty() {
+ write!(f, "<")?;
+ hir_fmt_generic_arguments(f, own_args.as_slice(), None)?;
+ write!(f, ">")?;
}
- ty.hir_fmt(f)?;
+ write!(f, " = ")?;
+ projection.term.hir_fmt(f)?;
}
+ _ => {}
}
first = false;
}
@@ -2177,154 +2022,52 @@
Ok(())
}
-impl HirDisplay for TraitRef {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- let trait_ = self.hir_trait_id();
- f.start_location_link(trait_.into());
- write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
- f.end_location_link();
- let substs = self.substitution.as_slice(Interner);
- hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
- }
-}
-
-impl<'db> HirDisplay for crate::next_solver::TraitRef<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TraitRef<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let trait_ = self.def_id.0;
f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
f.end_location_link();
let substs = self.args.as_slice();
- hir_fmt_generic_args(f, &substs[1..], None, substs[0].ty())
+ hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty()))
}
}
-impl HirDisplay for WhereClause {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- if f.should_truncate() {
- return write!(f, "{TYPE_HINT_TRUNCATION}");
- }
-
- match self {
- WhereClause::Implemented(trait_ref) => {
- trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
- write!(f, ": ")?;
- trait_ref.hir_fmt(f)?;
- }
- WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
- write!(f, "<")?;
- let trait_ref = &projection_ty.trait_ref(f.db);
- trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
- write!(f, " as ")?;
- trait_ref.hir_fmt(f)?;
- write!(f, ">::",)?;
- let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
- f.start_location_link(type_alias.into());
- write!(
- f,
- "{}",
- f.db.type_alias_signature(type_alias).name.display(f.db, f.edition()),
- )?;
- f.end_location_link();
- write!(f, " = ")?;
- ty.hir_fmt(f)?;
- }
- WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
-
- // FIXME implement these
- WhereClause::TypeOutlives(..) => {}
- WhereClause::LifetimeOutlives(..) => {}
- }
- Ok(())
- }
-}
-
-impl HirDisplay for LifetimeOutlives {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- self.a.hir_fmt(f)?;
- write!(f, ": ")?;
- self.b.hir_fmt(f)
- }
-}
-
-impl HirDisplay for Lifetime {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- self.interned().hir_fmt(f)
- }
-}
-
-impl HirDisplay for LifetimeData {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- match self {
- LifetimeData::Placeholder(idx) => {
- let id = lt_from_placeholder_idx(f.db, *idx).0;
- let generics = generics(f.db, id.parent);
- let param_data = &generics[id.local_id];
- write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
- Ok(())
- }
- LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
- LifetimeData::InferenceVar(_) => write!(f, "_"),
- LifetimeData::Static => write!(f, "'static"),
- LifetimeData::Error => {
- if cfg!(test) {
- write!(f, "'?")
- } else {
- write!(f, "'_")
- }
- }
- LifetimeData::Erased => write!(f, "'<erased>"),
- LifetimeData::Phantom(void, _) => match *void {},
- }
- }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Region<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Region<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.kind() {
- rustc_type_ir::RegionKind::ReEarlyParam(param) => {
+ RegionKind::ReEarlyParam(param) => {
let generics = generics(f.db, param.id.parent);
let param_data = &generics[param.id.local_id];
write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
Ok(())
}
- rustc_type_ir::RegionKind::ReBound(db, idx) => {
+ RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
write!(f, "?{}.{}", db.as_u32(), idx.var.as_u32())
}
- rustc_type_ir::RegionKind::ReVar(_) => write!(f, "_"),
- rustc_type_ir::RegionKind::ReStatic => write!(f, "'static"),
- rustc_type_ir::RegionKind::ReError(..) => {
+ RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => {
+ write!(f, "?c.{}", idx.var.as_u32())
+ }
+ RegionKind::ReVar(_) => write!(f, "_"),
+ RegionKind::ReStatic => write!(f, "'static"),
+ RegionKind::ReError(..) => {
if cfg!(test) {
write!(f, "'?")
} else {
write!(f, "'_")
}
}
- rustc_type_ir::RegionKind::ReErased => write!(f, "'<erased>"),
- rustc_type_ir::RegionKind::RePlaceholder(_) => write!(f, "<placeholder>"),
- rustc_type_ir::RegionKind::ReLateParam(_) => write!(f, "<late-param>"),
+ RegionKind::ReErased => write!(f, "'<erased>"),
+ RegionKind::RePlaceholder(_) => write!(f, "<placeholder>"),
+ RegionKind::ReLateParam(_) => write!(f, "<late-param>"),
}
}
}
-impl HirDisplay for DomainGoal {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- match self {
- DomainGoal::Holds(wc) => {
- write!(f, "Holds(")?;
- wc.hir_fmt(f)?;
- write!(f, ")")?;
- }
- _ => write!(f, "_")?,
- }
- Ok(())
- }
-}
-
-pub fn write_visibility(
+pub fn write_visibility<'db>(
module_id: ModuleId,
vis: Visibility,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
match vis {
Visibility::Public => write!(f, "pub "),
@@ -2346,28 +2089,30 @@
}
}
-pub trait HirDisplayWithExpressionStore {
+pub trait HirDisplayWithExpressionStore<'db> {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError>;
}
-impl<T: ?Sized + HirDisplayWithExpressionStore> HirDisplayWithExpressionStore for &'_ T {
+impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db>
+ for &'_ T
+{
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
T::hir_fmt(&**self, f, store)
}
}
-pub fn hir_display_with_store<'a, T: HirDisplayWithExpressionStore + 'a>(
+pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>(
value: T,
store: &'a ExpressionStore,
-) -> impl HirDisplay + 'a {
+) -> impl HirDisplay<'db> + 'a {
ExpressionStoreAdapter(value, store)
}
@@ -2379,15 +2124,15 @@
}
}
-impl<T: HirDisplayWithExpressionStore> HirDisplay for ExpressionStoreAdapter<'_, T> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
T::hir_fmt(&self.0, f, self.1)
}
}
-impl HirDisplayWithExpressionStore for LifetimeRefId {
+impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
match &store[*self] {
@@ -2407,10 +2152,10 @@
}
}
-impl HirDisplayWithExpressionStore for TypeRefId {
+impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
match &store[*self] {
@@ -2536,10 +2281,10 @@
}
}
-impl HirDisplayWithExpressionStore for ConstRef {
+impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
_store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
// FIXME
@@ -2549,10 +2294,10 @@
}
}
-impl HirDisplayWithExpressionStore for TypeBound {
+impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
match self {
@@ -2593,10 +2338,10 @@
}
}
-impl HirDisplayWithExpressionStore for Path {
+impl<'db> HirDisplayWithExpressionStore<'db> for Path {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
match (self.type_anchor(), self.kind()) {
@@ -2745,10 +2490,10 @@
}
}
-impl HirDisplayWithExpressionStore for hir_def::expr_store::path::GenericArg {
+impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg {
fn hir_fmt(
&self,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
store: &ExpressionStore,
) -> Result<(), HirDisplayError> {
match self {
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index aaf2747..b09d1fb 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -85,7 +85,7 @@
{
return DropGlue::None;
}
- db.field_types_ns(id.into())
+ db.field_types(id.into())
.iter()
.map(|(_, field_ty)| {
has_drop_glue_impl(
@@ -105,7 +105,7 @@
.variants
.iter()
.map(|&(variant, _, _)| {
- db.field_types_ns(variant.into())
+ db.field_types(variant.into())
.iter()
.map(|(_, field_ty)| {
has_drop_glue_impl(
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index b2406a0..437141e 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -7,7 +7,6 @@
TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId,
lang_item::LangItem, signatures::TraitFlags,
};
-use intern::Symbol;
use rustc_hash::FxHashSet;
use rustc_type_ir::{
AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _,
@@ -19,10 +18,10 @@
use crate::{
ImplTraitId,
db::{HirDatabase, InternedOpaqueTyId},
- lower_nextsolver::associated_ty_item_bounds,
+ lower::associated_ty_item_bounds,
next_solver::{
- Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TraitRef,
- TypingMode, infer::DbInternerInferExt, mk_param,
+ Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv, ParamTy,
+ SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt, mk_param,
},
traits::next_trait_solve_in_ctxt,
};
@@ -137,7 +136,7 @@
};
let interner = DbInterner::new_with(db, Some(krate), None);
- let predicates = db.generic_predicates_ns(def);
+ let predicates = db.generic_predicates(def);
// FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
// rust-analyzer yet
// https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
@@ -163,7 +162,7 @@
// but we don't have good way to render such locations.
// So, just return single boolean value for existence of such `Self` reference
fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
- db.generic_predicates_ns(trait_.into())
+ db.generic_predicates(trait_.into())
.iter()
.any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
}
@@ -379,7 +378,7 @@
}) = pred
&& let trait_data = db.trait_signature(pred_trait_ref.def_id.0)
&& trait_data.flags.contains(TraitFlags::AUTO)
- && let rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, .. }) =
+ && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) =
pred_trait_ref.self_ty().kind()
{
continue;
@@ -398,10 +397,7 @@
db: &dyn HirDatabase,
trait_: TraitId,
func: FunctionId,
- sig: &crate::next_solver::EarlyBinder<
- 'db,
- crate::next_solver::Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>,
- >,
+ sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
) -> bool {
let sig = sig.instantiate_identity();
@@ -410,10 +406,8 @@
parent: trait_.into(),
local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
});
- let self_param_ty = crate::next_solver::Ty::new(
- interner,
- rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, id: self_param_id }),
- );
+ let self_param_ty =
+ Ty::new(interner, rustc_type_ir::TyKind::Param(ParamTy { index: 0, id: self_param_id }));
// `self: Self` can't be dispatched on, but this is already considered dyn-compatible
// See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
@@ -441,21 +435,20 @@
// Type `U`
// FIXME: That seems problematic to fake a generic param like that?
- let unsized_self_ty =
- crate::next_solver::Ty::new_param(interner, self_param_id, u32::MAX, Symbol::empty());
+ let unsized_self_ty = Ty::new_param(interner, self_param_id, u32::MAX);
// `Receiver[Self => U]`
let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty);
let param_env = {
- let generic_predicates = &*db.generic_predicates_ns(func.into());
+ let generic_predicates = &*db.generic_predicates(func.into());
// Self: Unsize<U>
let unsize_predicate =
TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]);
// U: Trait<Arg1, ..., ArgN>
- let args = GenericArgs::for_item(interner, trait_.into(), |name, index, kind, _| {
- if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) }
+ let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _| {
+ if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, kind) }
});
let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args);
@@ -477,7 +470,7 @@
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let predicate =
TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]);
- let goal = crate::next_solver::Goal::new(interner, param_env, predicate);
+ let goal = Goal::new(interner, param_env, predicate);
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
// the receiver is dispatchable iff the obligation holds
@@ -488,26 +481,19 @@
fn receiver_for_self_ty<'db>(
interner: DbInterner<'db>,
func: FunctionId,
- receiver_ty: crate::next_solver::Ty<'db>,
- self_ty: crate::next_solver::Ty<'db>,
-) -> crate::next_solver::Ty<'db> {
- let args = crate::next_solver::GenericArgs::for_item(
- interner,
- SolverDefId::FunctionId(func),
- |name, index, kind, _| {
- if index == 0 { self_ty.into() } else { mk_param(interner, index, name, kind) }
- },
- );
+ receiver_ty: Ty<'db>,
+ self_ty: Ty<'db>,
+) -> Ty<'db> {
+ let args = GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _| {
+ if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) }
+ });
- crate::next_solver::EarlyBinder::bind(receiver_ty).instantiate(interner, args)
+ EarlyBinder::bind(receiver_ty).instantiate(interner, args)
}
fn contains_illegal_impl_trait_in_trait<'db>(
db: &'db dyn HirDatabase,
- sig: &crate::next_solver::EarlyBinder<
- 'db,
- crate::next_solver::Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>,
- >,
+ sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
) -> Option<MethodViolationCode> {
struct OpaqueTypeCollector(FxHashSet<InternedOpaqueTyId>);
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index e179e41..26e03aa 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -9,7 +9,6 @@
//! where parent follows the same scheme.
use std::ops;
-use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast as _};
use hir_def::{
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
TypeOrConstParamId, TypeParamId,
@@ -23,8 +22,6 @@
use itertools::chain;
use triomphe::Arc;
-use crate::{Interner, Substitution, db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx};
-
pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
let (params, store) = db.generic_params_and_store(def);
@@ -130,11 +127,16 @@
/// Returns total number of generic parameters in scope, including those from parent.
pub(crate) fn len(&self) -> usize {
- let parent = self.parent_generics().map_or(0, Generics::len);
+ let parent = self.len_parent();
let child = self.params.len();
parent + child
}
+ #[inline]
+ pub(crate) fn len_parent(&self) -> usize {
+ self.parent_generics().map_or(0, Generics::len)
+ }
+
/// Returns numbers of generic parameters excluding those from parent.
pub(crate) fn len_self(&self) -> usize {
self.params.len()
@@ -225,50 +227,6 @@
pub(crate) fn parent_generics(&self) -> Option<&Generics> {
self.parent_generics.as_deref()
}
-
- pub(crate) fn parent_or_self(&self) -> &Generics {
- self.parent_generics.as_deref().unwrap_or(self)
- }
-
- /// Returns a Substitution that replaces each parameter by a bound variable.
- pub(crate) fn bound_vars_subst(
- &self,
- db: &dyn HirDatabase,
- debruijn: DebruijnIndex,
- ) -> Substitution {
- Substitution::from_iter(
- Interner,
- self.iter_id().enumerate().map(|(idx, id)| match id {
- GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
- .to_const(Interner, db.const_param_ty(id))
- .cast(Interner),
- GenericParamId::TypeParamId(_) => {
- BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
- }
- GenericParamId::LifetimeParamId(_) => {
- BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
- }
- }),
- )
- }
-
- /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
- pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
- Substitution::from_iter(
- Interner,
- self.iter_id().enumerate().map(|(index, id)| match id {
- GenericParamId::TypeParamId(id) => {
- to_placeholder_idx(db, id.into(), index as u32).to_ty(Interner).cast(Interner)
- }
- GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into(), index as u32)
- .to_const(Interner, db.const_param_ty(id))
- .cast(Interner),
- GenericParamId::LifetimeParamId(id) => {
- lt_to_placeholder_idx(db, id, index as u32).to_lifetime(Interner).cast(Interner)
- }
- }),
- )
- }
}
pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option<usize> {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7249868..361e665 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -55,29 +55,24 @@
use triomphe::Arc;
use crate::{
- ImplTraitId, IncorrectGenericsLenKind, Interner, PathLoweringDiagnostic, TargetFeatures,
- TraitEnvironment,
+ ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures,
db::{HirDatabase, InternedClosureId, InternedOpaqueTyId},
- generics::Generics,
infer::{
coerce::{CoerceMany, DynamicCoerceMany},
diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
expr::ExprIsRead,
unify::InferenceTable,
},
- lower::diagnostics::TyLoweringDiagnostic,
- lower_nextsolver::{ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind},
+ lower::{
+ ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
+ },
mir::MirSpan,
next_solver::{
AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, Ty, TyKind,
Tys,
abi::Safety,
fold::fold_tys,
- infer::{
- DefineOpaqueTypes,
- traits::{Obligation, ObligationCause},
- },
- mapping::{ChalkToNextSolver, NextSolverToChalk},
+ infer::traits::{Obligation, ObligationCause},
},
traits::FnTrait,
utils::TargetFeatureIsSafeInTarget,
@@ -166,31 +161,6 @@
})
}
-/// Fully normalize all the types found within `ty` in context of `owner` body definition.
-///
-/// This is appropriate to use only after type-check: it assumes
-/// that normalization will succeed, for example.
-#[tracing::instrument(level = "debug", skip(db))]
-pub(crate) fn normalize(
- db: &dyn HirDatabase,
- trait_env: Arc<TraitEnvironment<'_>>,
- ty: crate::Ty,
-) -> crate::Ty {
- // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
- // works for the type case, so we check array unconditionally. Remove the array part
- // when the bug in chalk becomes fixed.
- if !ty.data(Interner).flags.intersects(crate::TypeFlags::HAS_PROJECTION)
- && !matches!(ty.kind(Interner), crate::TyKind::Array(..))
- {
- return ty;
- }
- let mut table = unify::InferenceTable::new(db, trait_env);
-
- let ty_with_vars = table.normalize_associated_types_in(ty.to_nextsolver(table.interner()));
- table.select_obligations_where_possible();
- table.resolve_completely(ty_with_vars).to_chalk(table.interner())
-}
-
/// Binding modes inferred for patterns.
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
@@ -789,8 +759,7 @@
/// and resolve the path via its methods. This will ensure proper error reporting.
pub(crate) resolver: Resolver<'db>,
target_features: OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>,
- generic_def: GenericDefId,
- generics: OnceCell<Generics>,
+ pub(crate) generic_def: GenericDefId,
table: unify::InferenceTable<'db>,
/// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>,
@@ -899,7 +868,6 @@
return_ty: types.error, // set in collect_* calls
types,
target_features: OnceCell::new(),
- generics: OnceCell::new(),
table,
tuple_field_accesses_rev: Default::default(),
resume_yield_tys: None,
@@ -928,10 +896,6 @@
}
}
- pub(crate) fn generics(&self) -> &Generics {
- self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def))
- }
-
#[inline]
fn krate(&self) -> Crate {
self.resolver.krate()
@@ -1159,7 +1123,7 @@
GenericArgs::for_item_with_defaults(
self.interner(),
va_list.into(),
- |_, _, id, _| self.table.next_var_for_param(id),
+ |_, id, _| self.table.next_var_for_param(id),
),
),
None => self.err_ty(),
@@ -1195,7 +1159,7 @@
},
);
let return_ty = self.insert_type_vars(return_ty);
- if let Some(rpits) = self.db.return_type_impl_traits_ns(func) {
+ if let Some(rpits) = self.db.return_type_impl_traits(func) {
let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default());
let result = self.insert_inference_vars_for_impl_trait(return_ty, &mut mode);
if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
@@ -1263,14 +1227,12 @@
if matches!(mode, ImplTraitReplacingMode::TypeAlias) {
// RPITs don't have `tait_coercion_table`, so use inserted inference
// vars for them.
- if let Some(ty) =
- self.result.type_of_rpit.get(idx.to_nextsolver(self.interner()))
- {
+ if let Some(ty) = self.result.type_of_rpit.get(idx) {
return *ty;
}
return ty;
}
- (self.db.return_type_impl_traits_ns(def), idx)
+ (self.db.return_type_impl_traits(def), idx)
}
ImplTraitId::TypeAliasImplTrait(def, idx) => {
if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
@@ -1279,17 +1241,15 @@
taits.insert(ty);
return ty;
}
- (self.db.type_alias_impl_traits_ns(def), idx)
+ (self.db.type_alias_impl_traits(def), idx)
}
- _ => unreachable!(),
};
let Some(impl_traits) = impl_traits else {
return ty;
};
- let bounds = (*impl_traits).as_ref().map_bound(|its| {
- its.impl_traits[idx.to_nextsolver(self.interner())].predicates.as_slice()
- });
- let var = match self.result.type_of_rpit.entry(idx.to_nextsolver(self.interner())) {
+ let bounds =
+ (*impl_traits).as_ref().map_bound(|its| its.impl_traits[idx].predicates.as_slice());
+ let var = match self.result.type_of_rpit.entry(idx) {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => *entry.insert(self.table.next_ty_var()),
};
@@ -1640,8 +1600,7 @@
match ty.kind() {
TyKind::Adt(adt_def, substs) => match adt_def.def_id().0 {
AdtId::StructId(struct_id) => {
- match self.db.field_types_ns(struct_id.into()).values().next_back().copied()
- {
+ match self.db.field_types(struct_id.into()).values().next_back().copied() {
Some(field) => {
ty = field.instantiate(self.interner(), substs);
}
@@ -1702,7 +1661,7 @@
.table
.infer_ctxt
.at(&ObligationCause::new(), self.table.trait_env.env)
- .eq(DefineOpaqueTypes::Yes, expected, actual)
+ .eq(expected, actual)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
if let Err(_err) = result {
// FIXME: Emit diagnostic.
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index 990281a..c128977 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -394,7 +394,7 @@
let struct_data = id.fields(ctx.db);
if let Some((last_field, _)) = struct_data.fields().iter().last() {
let last_field_ty =
- ctx.db.field_types_ns(id.into())[last_field].instantiate(ctx.interner(), subst);
+ ctx.db.field_types(id.into())[last_field].instantiate(ctx.interner(), subst);
pointer_kind(last_field_ty, ctx)
} else {
Ok(Some(PointerKind::Thin))
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 2637ed6..06f8307 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -11,8 +11,9 @@
type_ref::TypeRefId,
};
use rustc_type_ir::{
- ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable,
- TypeVisitable, TypeVisitableExt, TypeVisitor,
+ ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
+ CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ TypeVisitor,
inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _},
};
use tracing::debug;
@@ -22,11 +23,12 @@
db::{InternedClosure, InternedCoroutine},
infer::{BreakableKind, Diverges, coerce::CoerceMany},
next_solver::{
- AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig,
- PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind,
+ AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner,
+ ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate,
+ PredicateKind, SolverDefId, Ty, TyKind,
abi::Safety,
infer::{
- BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult,
+ BoundRegionConversionTime, InferOk, InferResult,
traits::{ObligationCause, PredicateObligations},
},
util::explicit_item_bounds,
@@ -72,6 +74,8 @@
let sig_ty = Ty::new_fn_ptr(interner, bound_sig);
let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into());
+ // FIXME: Make this an infer var and infer it later.
+ let tupled_upvars_ty = self.types.unit;
let (id, ty, resume_yield_tys) = match closure_kind {
ClosureKind::Coroutine(_) => {
let yield_ty = self.table.next_ty_var();
@@ -80,11 +84,11 @@
// FIXME: Infer the upvars later.
let parts = CoroutineArgsParts {
parent_args,
- kind_ty: Ty::new_unit(interner),
+ kind_ty: self.types.unit,
resume_ty,
yield_ty,
return_ty: body_ret_ty,
- tupled_upvars_ty: Ty::new_unit(interner),
+ tupled_upvars_ty,
};
let coroutine_id =
@@ -97,9 +101,7 @@
(None, coroutine_ty, Some((resume_ty, yield_ty)))
}
- // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`.
- // But for now we treat it as a closure.
- ClosureKind::Closure | ClosureKind::Async => {
+ ClosureKind::Closure => {
let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr));
match expected_kind {
Some(kind) => {
@@ -117,7 +119,7 @@
}
None => {}
};
- // FIXME: Infer the kind and the upvars later when needed.
+ // FIXME: Infer the kind later if needed.
let parts = ClosureArgsParts {
parent_args,
closure_kind_ty: Ty::from_closure_kind(
@@ -125,7 +127,7 @@
expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
),
closure_sig_as_fn_ptr_ty: sig_ty,
- tupled_upvars_ty: Ty::new_unit(interner),
+ tupled_upvars_ty,
};
let closure_ty = Ty::new_closure(
interner,
@@ -136,6 +138,61 @@
self.add_current_closure_dependency(closure_id);
(Some(closure_id), closure_ty, None)
}
+ ClosureKind::Async => {
+ // async closures always return the type ascribed after the `->` (if present),
+ // and yield `()`.
+ let bound_return_ty = bound_sig.skip_binder().output();
+ let bound_yield_ty = self.types.unit;
+ // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
+ let resume_ty = self.types.unit;
+
+ // FIXME: Infer the kind later if needed.
+ let closure_kind_ty = Ty::from_closure_kind(
+ interner,
+ expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
+ );
+
+ // FIXME: Infer captures later.
+ // `for<'env> fn() -> ()`, for no captures.
+ let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
+ interner,
+ Binder::bind_with_vars(
+ interner.mk_fn_sig([], self.types.unit, false, Safety::Safe, FnAbi::Rust),
+ BoundVarKinds::new_from_iter(
+ interner,
+ [BoundVarKind::Region(BoundRegionKind::ClosureEnv)],
+ ),
+ ),
+ );
+ let closure_args = CoroutineClosureArgs::new(
+ interner,
+ CoroutineClosureArgsParts {
+ parent_args,
+ closure_kind_ty,
+ signature_parts_ty: Ty::new_fn_ptr(
+ interner,
+ bound_sig.map_bound(|sig| {
+ interner.mk_fn_sig(
+ [
+ resume_ty,
+ Ty::new_tup_from_iter(interner, sig.inputs().iter()),
+ ],
+ Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]),
+ sig.c_variadic,
+ sig.safety,
+ sig.abi,
+ )
+ }),
+ ),
+ tupled_upvars_ty,
+ coroutine_captures_by_ref_ty,
+ },
+ );
+
+ let coroutine_id =
+ self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into();
+ (None, Ty::new_coroutine_closure(interner, coroutine_id, closure_args.args), None)
+ }
};
// Now go through the argument patterns
@@ -307,7 +364,7 @@
.table
.infer_ctxt
.at(&ObligationCause::new(), self.table.trait_env.env)
- .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig)
+ .eq(inferred_fnptr_sig, generalized_fnptr_sig)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
let resolved_sig =
@@ -692,18 +749,16 @@
let InferOk { value: (), obligations } = table
.infer_ctxt
.at(&cause, table.trait_env.env)
- .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?;
+ .eq(expected_ty, supplied_ty)?;
all_obligations.extend(obligations);
}
let supplied_output_ty = supplied_sig.output();
let cause = ObligationCause::new();
- let InferOk { value: (), obligations } =
- table.infer_ctxt.at(&cause, table.trait_env.env).eq(
- DefineOpaqueTypes::Yes,
- expected_sigs.liberated_sig.output(),
- supplied_output_ty,
- )?;
+ let InferOk { value: (), obligations } = table
+ .infer_ctxt
+ .at(&cause, table.trait_env.env)
+ .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
all_obligations.extend(obligations);
let inputs = supplied_sig
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 4620da7..78889cc 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -63,7 +63,7 @@
GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty,
TyKind,
infer::{
- DefineOpaqueTypes, InferCtxt, InferOk, InferResult,
+ InferCtxt, InferOk, InferResult,
relate::RelateResult,
select::{ImplSource, SelectionError},
traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations},
@@ -149,7 +149,7 @@
let res = if this.use_lub {
at.lub(b, a)
} else {
- at.sup(DefineOpaqueTypes::Yes, b, a)
+ at.sup(b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: b, obligations })
};
@@ -1460,19 +1460,12 @@
//
// Another example is `break` with no argument expression.
assert!(expression_ty.is_unit(), "if let hack without unit type");
- icx.table
- .infer_ctxt
- .at(cause, icx.table.trait_env.env)
- .eq(
- // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
- DefineOpaqueTypes::Yes,
- expected,
- found,
- )
- .map(|infer_ok| {
+ icx.table.infer_ctxt.at(cause, icx.table.trait_env.env).eq(expected, found).map(
+ |infer_ok| {
icx.table.register_infer_ok(infer_ok);
expression_ty
- })
+ },
+ )
};
debug!(?result);
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs
index 39e70c2..844eb02 100644
--- a/crates/hir-ty/src/infer/diagnostics.rs
+++ b/crates/hir-ty/src/infer/diagnostics.rs
@@ -15,8 +15,8 @@
use crate::{
InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
db::HirDatabase,
- lower_nextsolver::path::{PathDiagnosticCallback, PathLoweringContext},
- lower_nextsolver::{LifetimeElisionKind, TyLoweringContext},
+ lower::path::{PathDiagnosticCallback, PathLoweringContext},
+ lower::{LifetimeElisionKind, TyLoweringContext},
};
// Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 179eacc..fd4e374 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -18,7 +18,7 @@
use intern::sym;
use rustc_ast_ir::Mutability;
use rustc_type_ir::{
- AliasTyKind, InferTy, Interner,
+ CoroutineArgs, CoroutineArgsParts, InferTy, Interner,
inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _},
};
use syntax::ast::RangeOp;
@@ -29,6 +29,7 @@
IncorrectGenericsLenKind, Rawness, TraitEnvironment,
autoderef::overloaded_deref_ty,
consteval,
+ db::InternedCoroutine,
generics::generics,
infer::{
AllowTwoPhase, BreakableKind,
@@ -37,16 +38,16 @@
pat::contains_explicit_ref_binding,
},
lang_items::lang_items_for_bin_op,
- lower_nextsolver::{
+ lower::{
LifetimeElisionKind, lower_mutability,
path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
},
method_resolution::{self, VisibleFromModule},
next_solver::{
- AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind,
+ Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind,
TypeError,
infer::{
- DefineOpaqueTypes, InferOk,
+ InferOk,
traits::{Obligation, ObligationCause},
},
obligation_ctxt::ObligationCtxt,
@@ -564,7 +565,7 @@
match def_id {
_ if fields.is_empty() => {}
Some(def) => {
- let field_types = self.db.field_types_ns(def);
+ let field_types = self.db.field_types(def);
let variant_data = def.fields(self.db);
let visibilities = self.db.field_visibilities(def);
for field in fields.iter() {
@@ -1132,18 +1133,26 @@
inner_ty: Ty<'db>,
tgt_expr: ExprId,
) -> Ty<'db> {
- // Use the first type parameter as the output type of future.
- // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
- let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- Ty::new_alias(
+ let coroutine_id = InternedCoroutine(self.owner, tgt_expr);
+ let coroutine_id = self.db.intern_coroutine(coroutine_id).into();
+ let parent_args = GenericArgs::identity_for_item(self.interner(), self.generic_def.into());
+ Ty::new_coroutine(
self.interner(),
- AliasTyKind::Opaque,
- AliasTy::new(
+ coroutine_id,
+ CoroutineArgs::new(
self.interner(),
- opaque_ty_id,
- GenericArgs::new_from_iter(self.interner(), [inner_ty.into()]),
- ),
+ CoroutineArgsParts {
+ parent_args,
+ kind_ty: self.types.unit,
+ // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
+ resume_ty: self.types.unit,
+ yield_ty: self.types.unit,
+ return_ty: inner_ty,
+ // FIXME: Infer upvars.
+ tupled_upvars_ty: self.types.unit,
+ },
+ )
+ .args,
)
}
@@ -1333,7 +1342,7 @@
self.interner(),
box_id.into(),
[inner_ty.into()],
- |_, _, id, _| self.table.next_var_for_param(id),
+ |_, id, _| self.table.next_var_for_param(id),
),
)
} else {
@@ -1622,7 +1631,7 @@
}
return None;
}
- let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id]
+ let ty = self.db.field_types(field_id.parent)[field_id.local_id]
.instantiate(interner, parameters);
Some((Either::Left(field_id), ty))
});
@@ -1637,7 +1646,7 @@
None => {
let (field_id, subst) = private_field?;
let adjustments = autoderef.adjust_steps();
- let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id]
+ let ty = self.db.field_types(field_id.parent)[field_id.local_id]
.instantiate(self.interner(), subst);
let ty = self.process_remote_user_written_ty(ty);
@@ -2122,7 +2131,7 @@
.table
.infer_ctxt
.at(&ObligationCause::new(), this.table.trait_env.env)
- .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty);
+ .eq(formal_input_ty, coerced_ty);
// If neither check failed, the types are compatible
match formal_ty_error {
@@ -2320,7 +2329,7 @@
let callable_ty = self.table.try_structurally_resolve_type(callable_ty);
if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() {
let generic_predicates =
- self.db.generic_predicates_ns(GenericDefId::from_callable(self.db, fn_def.0));
+ self.db.generic_predicates(GenericDefId::from_callable(self.db, fn_def.0));
if let Some(predicates) = generic_predicates.instantiate(self.interner(), parameters) {
let interner = self.interner();
let param_env = self.table.trait_env.env;
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index 9edbc9d..71a9c94 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -18,7 +18,7 @@
use crate::{
Adjust, Adjustment, AutoBorrow, OverloadedDeref,
infer::{Expectation, InferenceContext, expr::ExprIsRead},
- lower_nextsolver::lower_mutability,
+ lower::lower_mutability,
next_solver::TyKind,
};
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 452ae31..8019844 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -19,7 +19,7 @@
AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch,
coerce::CoerceNever, expr::ExprIsRead,
},
- lower_nextsolver::lower_mutability,
+ lower::lower_mutability,
next_solver::{GenericArgs, Ty, TyKind},
};
@@ -59,7 +59,7 @@
match def {
_ if subs.is_empty() => {}
Some(def) => {
- let field_types = self.db.field_types_ns(def);
+ let field_types = self.db.field_types(def);
let variant_data = def.fields(self.db);
let visibilities = self.db.field_visibilities(def);
@@ -128,7 +128,7 @@
match def {
_ if subs.len() == 0 => {}
Some(def) => {
- let field_types = self.db.field_types_ns(def);
+ let field_types = self.db.field_types(def);
let variant_data = def.fields(self.db);
let visibilities = self.db.field_visibilities(def);
@@ -358,7 +358,7 @@
self.interner(),
box_adt.into(),
std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
- |_, _, id, _| self.table.next_var_for_param(id),
+ |_, id, _| self.table.next_var_for_param(id),
),
)
}
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index f70ed90..2dae7cb 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -13,7 +13,7 @@
InferenceDiagnostic, ValueTyDefId,
generics::generics,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
- lower_nextsolver::LifetimeElisionKind,
+ lower::LifetimeElisionKind,
method_resolution::{self, VisibleFromModule},
next_solver::{
GenericArg, GenericArgs, TraitRef, Ty,
@@ -118,7 +118,7 @@
self.interner(),
generic_def.into(),
self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)),
- |_, _, id, _| GenericArg::error_from_id(self.interner(), id),
+ |_, id, _| GenericArg::error_from_id(self.interner(), id),
);
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
@@ -221,7 +221,7 @@
def: GenericDefId,
subst: GenericArgs<'db>,
) {
- let predicates = self.db.generic_predicates_ns(def);
+ let predicates = self.db.generic_predicates(def);
let interner = self.interner();
let param_env = self.table.trait_env.env;
if let Some(predicates) = predicates.instantiate(self.interner(), subst) {
@@ -352,7 +352,7 @@
self.interner(),
trait_.into(),
[ty.into()],
- |_, _, id, _| self.table.next_var_for_param(id),
+ |_, id, _| self.table.next_var_for_param(id),
);
let trait_ref = TraitRef::new(self.interner(), trait_.into(), args);
self.table.register_predicate(Obligation::new(
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 8f754f0..a18cdda 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -25,7 +25,7 @@
SolverDefId, SolverDefIds, TraitRef, Ty, TyKind, TypingMode,
fulfill::{FulfillmentCtxt, NextSolverError},
infer::{
- DbInternerInferExt, DefineOpaqueTypes, InferCtxt, InferOk, InferResult,
+ DbInternerInferExt, InferCtxt, InferOk, InferResult,
at::ToTrace,
snapshot::CombinedSnapshot,
traits::{Obligation, ObligationCause, PredicateObligation},
@@ -148,7 +148,7 @@
let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys);
let mut ctxt = ObligationCtxt::new(&infcx);
let can_unify = at
- .eq(DefineOpaqueTypes::No, ty1_with_vars, ty2_with_vars)
+ .eq(ty1_with_vars, ty2_with_vars)
.map(|infer_ok| ctxt.register_infer_ok_obligations(infer_ok))
.is_ok();
can_unify && select(&mut ctxt).is_empty()
@@ -452,11 +452,7 @@
/// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
/// caller needs to deal with them.
pub(crate) fn try_unify<T: ToTrace<'db>>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> {
- self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq(
- DefineOpaqueTypes::Yes,
- t1,
- t2,
- )
+ self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq(t1, t2)
}
pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> {
@@ -804,7 +800,7 @@
while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
let struct_data = id.fields(self.db);
if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
- let last_field_ty = self.db.field_types_ns(id.into())[last_field]
+ let last_field_ty = self.db.field_types(id.into())[last_field]
.instantiate(self.interner(), subst);
if structs.contains(&ty) {
// A struct recursively contains itself as a tail field somewhere.
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index 826f19c..5e742bb 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -1,60 +1,62 @@
//! Type inhabitedness logic.
use std::ops::ControlFlow::{self, Break, Continue};
-use chalk_ir::{
- DebruijnIndex,
- visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-};
use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility};
use rustc_hash::FxHashSet;
+use rustc_type_ir::{
+ TypeSuperVisitable, TypeVisitable, TypeVisitor,
+ inherent::{AdtDef, IntoKind},
+};
use triomphe::Arc;
use crate::{
- AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind,
+ TraitEnvironment,
consteval::try_const_usize,
db::HirDatabase,
- next_solver::{DbInterner, mapping::ChalkToNextSolver},
+ next_solver::{
+ DbInterner, EarlyBinder, GenericArgs, Ty, TyKind,
+ infer::{InferCtxt, traits::ObligationCause},
+ obligation_ctxt::ObligationCtxt,
+ },
};
// FIXME: Turn this into a query, it can be quite slow
/// Checks whether a type is visibly uninhabited from a particular module.
-pub(crate) fn is_ty_uninhabited_from(
- db: &dyn HirDatabase,
- ty: &Ty,
+pub(crate) fn is_ty_uninhabited_from<'db>(
+ infcx: &InferCtxt<'db>,
+ ty: Ty<'db>,
target_mod: ModuleId,
- env: Arc<TraitEnvironment<'_>>,
+ env: Arc<TraitEnvironment<'db>>,
) -> bool {
let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
- let mut uninhabited_from =
- UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
- let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
+ let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env);
+ let inhabitedness = ty.visit_with(&mut uninhabited_from);
inhabitedness == BREAK_VISIBLY_UNINHABITED
}
// FIXME: Turn this into a query, it can be quite slow
/// Checks whether a variant is visibly uninhabited from a particular module.
-pub(crate) fn is_enum_variant_uninhabited_from(
- db: &dyn HirDatabase,
+pub(crate) fn is_enum_variant_uninhabited_from<'db>(
+ infcx: &InferCtxt<'db>,
variant: EnumVariantId,
- subst: &Substitution,
+ subst: GenericArgs<'db>,
target_mod: ModuleId,
- env: Arc<TraitEnvironment<'_>>,
+ env: Arc<TraitEnvironment<'db>>,
) -> bool {
let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
- let mut uninhabited_from =
- UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
+ let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env);
let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst);
inhabitedness == BREAK_VISIBLY_UNINHABITED
}
-struct UninhabitedFrom<'a> {
+struct UninhabitedFrom<'a, 'db> {
target_mod: ModuleId,
- recursive_ty: FxHashSet<Ty>,
+ recursive_ty: FxHashSet<Ty<'db>>,
// guard for preventing stack overflow in non trivial non terminating types
max_depth: usize,
- db: &'a dyn HirDatabase,
- env: Arc<TraitEnvironment<'a>>,
+ infcx: &'a InferCtxt<'db>,
+ env: Arc<TraitEnvironment<'db>>,
}
const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
@@ -62,63 +64,73 @@
#[derive(PartialEq, Eq)]
struct VisiblyUninhabited;
-impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
- type BreakTy = VisiblyUninhabited;
+impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> {
+ type Result = ControlFlow<VisiblyUninhabited>;
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
- self
- }
-
- fn visit_ty(
- &mut self,
- ty: &Ty,
- outer_binder: DebruijnIndex,
- ) -> ControlFlow<VisiblyUninhabited> {
- if self.recursive_ty.contains(ty) || self.max_depth == 0 {
+ fn visit_ty(&mut self, mut ty: Ty<'db>) -> ControlFlow<VisiblyUninhabited> {
+ if self.recursive_ty.contains(&ty) || self.max_depth == 0 {
// rustc considers recursive types always inhabited. I think it is valid to consider
// recursive types as always uninhabited, but we should do what rustc is doing.
return CONTINUE_OPAQUELY_INHABITED;
}
- self.recursive_ty.insert(ty.clone());
+ self.recursive_ty.insert(ty);
self.max_depth -= 1;
- let interner = DbInterner::new_with(self.db, None, None);
- let r = match ty.kind(Interner) {
- TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
+
+ if matches!(ty.kind(), TyKind::Alias(..)) {
+ let mut ocx = ObligationCtxt::new(self.infcx);
+ match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env.env, ty) {
+ Ok(it) => ty = it,
+ Err(_) => return CONTINUE_OPAQUELY_INHABITED,
+ }
+ }
+
+ let r = match ty.kind() {
+ TyKind::Adt(adt, subst) => self.visit_adt(adt.def_id().0, subst),
TyKind::Never => BREAK_VISIBLY_UNINHABITED,
- TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
- TyKind::Array(item_ty, len) => {
- match try_const_usize(self.db, len.to_nextsolver(interner)) {
- Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
- Some(1..) => item_ty.super_visit_with(self, outer_binder),
- }
- }
- TyKind::Alias(AliasTy::Projection(projection)) => {
- // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
- // `TyKind::AssociatedType`, but perhaps in the future it will.
- let normalized = self.db.normalize_projection(projection.clone(), self.env.clone());
- self.visit_ty(&normalized, outer_binder)
- }
+ TyKind::Tuple(..) => ty.super_visit_with(self),
+ TyKind::Array(item_ty, len) => match try_const_usize(self.infcx.interner.db, len) {
+ Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
+ Some(1..) => item_ty.visit_with(self),
+ },
_ => CONTINUE_OPAQUELY_INHABITED,
};
- self.recursive_ty.remove(ty);
+ self.recursive_ty.remove(&ty);
self.max_depth += 1;
r
}
-
- fn interner(&self) -> Interner {
- Interner
- }
}
-impl UninhabitedFrom<'_> {
- fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
+impl<'a, 'db> UninhabitedFrom<'a, 'db> {
+ fn new(
+ infcx: &'a InferCtxt<'db>,
+ target_mod: ModuleId,
+ env: Arc<TraitEnvironment<'db>>,
+ ) -> Self {
+ Self { target_mod, recursive_ty: FxHashSet::default(), max_depth: 500, infcx, env }
+ }
+
+ #[inline]
+ fn interner(&self) -> DbInterner<'db> {
+ self.infcx.interner
+ }
+
+ #[inline]
+ fn db(&self) -> &'db dyn HirDatabase {
+ self.interner().db
+ }
+
+ fn visit_adt(
+ &mut self,
+ adt: AdtId,
+ subst: GenericArgs<'db>,
+ ) -> ControlFlow<VisiblyUninhabited> {
// An ADT is uninhabited iff all its variants uninhabited.
match adt {
// rustc: For now, `union`s are never considered uninhabited.
AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
AdtId::StructId(s) => self.visit_variant(s.into(), subst),
AdtId::EnumId(e) => {
- let enum_data = e.enum_variants(self.db);
+ let enum_data = e.enum_variants(self.db());
for &(variant, _, _) in enum_data.variants.iter() {
let variant_inhabitedness = self.visit_variant(variant.into(), subst);
@@ -135,17 +147,17 @@
fn visit_variant(
&mut self,
variant: VariantId,
- subst: &Substitution,
+ subst: GenericArgs<'db>,
) -> ControlFlow<VisiblyUninhabited> {
- let variant_data = variant.fields(self.db);
+ let variant_data = variant.fields(self.db());
let fields = variant_data.fields();
if fields.is_empty() {
return CONTINUE_OPAQUELY_INHABITED;
}
let is_enum = matches!(variant, VariantId::EnumVariantId(..));
- let field_tys = self.db.field_types(variant);
- let field_vis = if is_enum { None } else { Some(self.db.field_visibilities(variant)) };
+ let field_tys = self.db().field_types(variant);
+ let field_vis = if is_enum { None } else { Some(self.db().field_visibilities(variant)) };
for (fid, _) in fields.iter() {
self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid], subst)?;
@@ -156,12 +168,12 @@
fn visit_field(
&mut self,
vis: Option<Visibility>,
- ty: &Binders<Ty>,
- subst: &Substitution,
+ ty: &EarlyBinder<'db, Ty<'db>>,
+ subst: GenericArgs<'db>,
) -> ControlFlow<VisiblyUninhabited> {
- if vis.is_none_or(|it| it.is_visible_from(self.db, self.target_mod)) {
- let ty = ty.clone().substitute(Interner, subst);
- ty.visit_with(self, DebruijnIndex::INNERMOST)
+ if vis.is_none_or(|it| it.is_visible_from(self.db(), self.target_mod)) {
+ let ty = ty.instantiate(self.interner(), subst);
+ ty.visit_with(self)
} else {
CONTINUE_OPAQUELY_INHABITED
}
diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs
deleted file mode 100644
index 57ef552..0000000
--- a/crates/hir-ty/src/interner.rs
+++ /dev/null
@@ -1,403 +0,0 @@
-//! Implementation of the Chalk `Interner` trait, which allows customizing the
-//! representation of the various objects Chalk deals with (types, goals etc.).
-
-use crate::{
- AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, FnAbi,
- FnDefId, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, Lifetime, LifetimeData,
- OpaqueTy, OpaqueTyId, ProgramClause, ProjectionTy, QuantifiedWhereClause,
- QuantifiedWhereClauses, Substitution, Ty, TyKind, VariableKind, chalk_db, tls,
-};
-use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance};
-use hir_def::TypeAliasId;
-use intern::{Interned, impl_internable};
-use smallvec::SmallVec;
-use std::fmt;
-use triomphe::Arc;
-
-type TyData = chalk_ir::TyData<Interner>;
-type VariableKinds = chalk_ir::VariableKinds<Interner>;
-type Goals = chalk_ir::Goals<Interner>;
-type ProgramClauseData = chalk_ir::ProgramClauseData<Interner>;
-type Constraint = chalk_ir::Constraint<Interner>;
-type Constraints = chalk_ir::Constraints<Interner>;
-type ProgramClauses = chalk_ir::ProgramClauses<Interner>;
-
-#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Interner;
-
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapper<T>(pub(crate) T);
-
-impl<T: fmt::Debug> fmt::Debug for InternedWrapper<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.0, f)
- }
-}
-
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapperNoDebug<T>(pub(crate) T);
-
-impl<T> std::ops::Deref for InternedWrapper<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl_internable!(
- InternedWrapper<Vec<VariableKind>>,
- InternedWrapper<SmallVec<[GenericArg; 2]>>,
- InternedWrapper<TyData>,
- InternedWrapper<LifetimeData>,
- InternedWrapper<ConstData>,
- InternedWrapper<ConstScalar>,
- InternedWrapper<Vec<CanonicalVarKind>>,
- InternedWrapper<Box<[ProgramClause]>>,
- InternedWrapper<Vec<QuantifiedWhereClause>>,
- InternedWrapper<SmallVec<[Variance; 16]>>,
-);
-
-impl chalk_ir::interner::Interner for Interner {
- type InternedType = Interned<InternedWrapper<TyData>>;
- type InternedLifetime = Interned<InternedWrapper<LifetimeData>>;
- type InternedConst = Interned<InternedWrapper<ConstData>>;
- type InternedConcreteConst = ConstScalar;
- type InternedGenericArg = GenericArgData;
- // We could do the following, but that saves "only" 20mb on self while increasing inference
- // time by ~2.5%
- // type InternedGoal = Interned<InternedWrapper<GoalData>>;
- type InternedGoal = Arc<GoalData>;
- type InternedGoals = Vec<Goal>;
- type InternedSubstitution = Interned<InternedWrapper<SmallVec<[GenericArg; 2]>>>;
- type InternedProgramClauses = Interned<InternedWrapper<Box<[ProgramClause]>>>;
- type InternedProgramClause = ProgramClauseData;
- type InternedQuantifiedWhereClauses = Interned<InternedWrapper<Vec<QuantifiedWhereClause>>>;
- type InternedVariableKinds = Interned<InternedWrapper<Vec<VariableKind>>>;
- type InternedCanonicalVarKinds = Interned<InternedWrapper<Vec<CanonicalVarKind>>>;
- type InternedConstraints = Vec<InEnvironment<Constraint>>;
- type InternedVariances = SmallVec<[Variance; 16]>;
- type DefId = salsa::Id;
- type InternedAdtId = hir_def::AdtId;
- type Identifier = TypeAliasId;
- type FnAbi = FnAbi;
-
- fn debug_adt_id(
- type_kind_id: chalk_db::AdtId,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
- }
-
- fn debug_trait_id(
- type_kind_id: chalk_db::TraitId,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
- }
-
- fn debug_assoc_type_id(
- id: chalk_db::AssocTypeId,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
- }
-
- fn debug_opaque_ty_id(
- opaque_ty_id: OpaqueTyId,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "OpaqueTy#{:?}", opaque_ty_id.0))
- }
-
- fn debug_fn_def_id(fn_def_id: FnDefId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt)))
- }
-
- fn debug_closure_id(
- _fn_def_id: ClosureId,
- _fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- None
- }
-
- fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- use std::fmt::Debug;
- match alias {
- AliasTy::Projection(projection_ty) => Interner::debug_projection_ty(projection_ty, fmt),
- AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)),
- }
- }
-
- fn debug_projection_ty(
- proj: &ProjectionTy,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt)))
- .or_else(|| Some(fmt.write_str("ProjectionTy")))
- }
-
- fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id))
- }
-
- fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", ty.data(Interner)))
- }
-
- fn debug_lifetime(lifetime: &Lifetime, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", lifetime.data(Interner)))
- }
-
- fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", constant.data(Interner)))
- }
-
- fn debug_generic_arg(
- parameter: &GenericArg,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug()))
- }
-
- fn debug_variable_kinds(
- variable_kinds: &VariableKinds,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner)))
- }
-
- fn debug_variable_kinds_with_angles(
- variable_kinds: &VariableKinds,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner)))
- }
-
- fn debug_canonical_var_kinds(
- canonical_var_kinds: &CanonicalVarKinds,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner)))
- }
- fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- let goal_data = goal.data(Interner);
- Some(write!(fmt, "{goal_data:?}"))
- }
- fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", goals.debug(Interner)))
- }
- fn debug_program_clause_implication(
- pci: &ProgramClauseImplication<Self>,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", pci.debug(Interner)))
- }
- fn debug_program_clause(
- clause: &ProgramClause,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", clause.data(Interner)))
- }
- fn debug_program_clauses(
- clauses: &ProgramClauses,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", clauses.as_slice(Interner)))
- }
- fn debug_substitution(
- substitution: &Substitution,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", substitution.debug(Interner)))
- }
- fn debug_separator_trait_ref(
- separator_trait_ref: &SeparatorTraitRef<'_, Interner>,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner)))
- }
-
- fn debug_quantified_where_clauses(
- clauses: &QuantifiedWhereClauses,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- Some(write!(fmt, "{:?}", clauses.as_slice(Interner)))
- }
-
- fn debug_constraints(
- _clauses: &Constraints,
- _fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- None
- }
-
- fn intern_ty(self, kind: TyKind) -> Self::InternedType {
- let flags = kind.compute_flags(self);
- Interned::new(InternedWrapper(TyData { kind, flags }))
- }
-
- fn ty_data(self, ty: &Self::InternedType) -> &TyData {
- &ty.0
- }
-
- fn intern_lifetime(self, lifetime: LifetimeData) -> Self::InternedLifetime {
- Interned::new(InternedWrapper(lifetime))
- }
-
- fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &LifetimeData {
- &lifetime.0
- }
-
- fn intern_const(self, constant: ConstData) -> Self::InternedConst {
- Interned::new(InternedWrapper(constant))
- }
-
- fn const_data(self, constant: &Self::InternedConst) -> &ConstData {
- &constant.0
- }
-
- fn const_eq(
- self,
- _ty: &Self::InternedType,
- c1: &Self::InternedConcreteConst,
- c2: &Self::InternedConcreteConst,
- ) -> bool {
- !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2)
- }
-
- fn intern_generic_arg(self, parameter: GenericArgData) -> Self::InternedGenericArg {
- parameter
- }
-
- fn generic_arg_data(self, parameter: &Self::InternedGenericArg) -> &GenericArgData {
- parameter
- }
-
- fn intern_goal(self, goal: GoalData) -> Self::InternedGoal {
- Arc::new(goal)
- }
-
- fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData {
- goal
- }
-
- fn intern_goals<E>(
- self,
- data: impl IntoIterator<Item = Result<Goal, E>>,
- ) -> Result<Self::InternedGoals, E> {
- // let hash =
- // std::hash::BuildHasher::hash_one(&BuildHasherDefault::<FxHasher>::default(), &goal);
- // Interned::new(InternedWrapper(PreHashedWrapper(goal, hash)))
- data.into_iter().collect()
- }
-
- fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] {
- goals
- }
-
- fn intern_substitution<E>(
- self,
- data: impl IntoIterator<Item = Result<GenericArg, E>>,
- ) -> Result<Self::InternedSubstitution, E> {
- Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
- }
-
- fn substitution_data(self, substitution: &Self::InternedSubstitution) -> &[GenericArg] {
- &substitution.as_ref().0
- }
-
- fn intern_program_clause(self, data: ProgramClauseData) -> Self::InternedProgramClause {
- data
- }
-
- fn program_clause_data(self, clause: &Self::InternedProgramClause) -> &ProgramClauseData {
- clause
- }
-
- fn intern_program_clauses<E>(
- self,
- data: impl IntoIterator<Item = Result<ProgramClause, E>>,
- ) -> Result<Self::InternedProgramClauses, E> {
- Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
- }
-
- fn program_clauses_data(self, clauses: &Self::InternedProgramClauses) -> &[ProgramClause] {
- clauses
- }
-
- fn intern_quantified_where_clauses<E>(
- self,
- data: impl IntoIterator<Item = Result<QuantifiedWhereClause, E>>,
- ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
- Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
- }
-
- fn quantified_where_clauses_data(
- self,
- clauses: &Self::InternedQuantifiedWhereClauses,
- ) -> &[QuantifiedWhereClause] {
- clauses
- }
-
- fn intern_generic_arg_kinds<E>(
- self,
- data: impl IntoIterator<Item = Result<VariableKind, E>>,
- ) -> Result<Self::InternedVariableKinds, E> {
- Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
- }
-
- fn variable_kinds_data(self, parameter_kinds: &Self::InternedVariableKinds) -> &[VariableKind] {
- ¶meter_kinds.as_ref().0
- }
-
- fn intern_canonical_var_kinds<E>(
- self,
- data: impl IntoIterator<Item = Result<CanonicalVarKind, E>>,
- ) -> Result<Self::InternedCanonicalVarKinds, E> {
- Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
- }
-
- fn canonical_var_kinds_data(
- self,
- canonical_var_kinds: &Self::InternedCanonicalVarKinds,
- ) -> &[CanonicalVarKind] {
- canonical_var_kinds
- }
- fn intern_constraints<E>(
- self,
- data: impl IntoIterator<Item = Result<InEnvironment<Constraint>, E>>,
- ) -> Result<Self::InternedConstraints, E> {
- data.into_iter().collect()
- }
- fn constraints_data(
- self,
- constraints: &Self::InternedConstraints,
- ) -> &[InEnvironment<Constraint>] {
- constraints
- }
-
- fn intern_variances<E>(
- self,
- data: impl IntoIterator<Item = Result<Variance, E>>,
- ) -> Result<Self::InternedVariances, E> {
- data.into_iter().collect::<Result<_, _>>()
- }
-
- fn variances_data(self, variances: &Self::InternedVariances) -> &[Variance] {
- variances
- }
-}
-
-impl chalk_ir::interner::HasInterner for Interner {
- type Interner = Self;
-}
-
-#[macro_export]
-macro_rules! has_interner {
- ($t:ty) => {
- impl HasInterner for $t {
- type Interner = $crate::Interner;
- }
- };
-}
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index a857602..fc0b9d3 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -138,7 +138,7 @@
// * #[repr(simd)] struct S([T; 4])
//
// where T is a primitive scalar (integer/float/pointer).
- let fields = db.field_types_ns(id.into());
+ let fields = db.field_types(id.into());
let mut fields = fields.iter();
let Some(TyKind::Array(e_ty, e_len)) = fields
.next()
@@ -401,7 +401,7 @@
fd: LocalFieldId,
args: &GenericArgs<'a>,
) -> Ty<'a> {
- db.field_types_ns(def)[fd].instantiate(DbInterner::new_with(db, None, None), args)
+ db.field_types(def)[fd].instantiate(DbInterner::new_with(db, None, None), args)
}
fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 734483a..25579e0 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -23,23 +23,16 @@
extern crate self as hir_ty;
-mod builder;
-mod chalk_db;
-mod chalk_ext;
mod infer;
mod inhabitedness;
-mod interner;
mod lower;
-mod lower_nextsolver;
-mod mapping;
pub mod next_solver;
+mod specialization;
mod target_feature;
-mod tls;
mod utils;
pub mod autoderef;
pub mod consteval;
-mod consteval_chalk;
pub mod db;
pub mod diagnostics;
pub mod display;
@@ -61,42 +54,32 @@
use std::hash::Hash;
-use chalk_ir::{
- VariableKinds,
- fold::{Shift, TypeFoldable},
- interner::HasInterner,
-};
-use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness};
+use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness};
use hir_expand::name::Name;
use indexmap::{IndexMap, map::Entry};
use intern::{Symbol, sym};
-use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use rustc_type_ir::{
- TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
+ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
inherent::{IntoKind, SliceLike, Ty as _},
};
use syntax::ast::{ConstArg, make};
use traits::FnTrait;
use triomphe::Arc;
-#[cfg(not(debug_assertions))]
-use crate::next_solver::ErrorGuaranteed;
use crate::{
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
- generics::Generics,
infer::unify::InferenceTable,
next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
+ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical,
+ CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, PolyFnSig, Predicate,
+ Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
},
};
pub use autoderef::autoderef;
-pub use builder::{ParamKind, TyBuilder};
-pub use chalk_ext::*;
pub use infer::{
Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult,
InferenceTyDiagnosticSource, OverloadedDeref, PointerCast,
@@ -104,15 +87,9 @@
closure::analysis::{CaptureKind, CapturedItem},
could_coerce, could_unify, could_unify_deeply,
};
-pub use interner::Interner;
-pub use lower::{ImplTraitLoweringMode, ParamLoweringMode, TyDefId, ValueTyDefId, diagnostics::*};
-pub use lower_nextsolver::{
- LifetimeElisionKind, TyLoweringContext, associated_type_shorthand_candidates,
-};
-pub use mapping::{
- ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
- lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
- to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index,
+pub use lower::{
+ LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId,
+ associated_type_shorthand_candidates, diagnostics::*,
};
pub use method_resolution::check_orphan_rules;
pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
@@ -122,79 +99,6 @@
TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits,
is_fn_unsafe_to_call, target_feature_is_safe_in_target,
};
-pub use variance::Variance;
-
-use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Safety, Scalar};
-
-pub(crate) type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
-pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
-pub(crate) type FnDefId = chalk_ir::FnDefId<Interner>;
-pub(crate) type ClosureId = chalk_ir::ClosureId<Interner>;
-pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
-pub(crate) type PlaceholderIndex = chalk_ir::PlaceholderIndex;
-
-pub(crate) type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
-
-pub(crate) type VariableKind = chalk_ir::VariableKind<Interner>;
-/// Represents generic parameters and an item bound by them. When the item has parent, the binders
-/// also contain the generic parameters for its parent. See chalk's documentation for details.
-///
-/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
-/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
-/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
-/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
-/// motivation in detail.
-pub(crate) type Binders<T> = chalk_ir::Binders<T>;
-/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
-/// it contains generic arguments for both its parent and itself. See chalk's documentation for
-/// details.
-///
-/// See `Binders` for the constraint on the ordering.
-pub(crate) type Substitution = chalk_ir::Substitution<Interner>;
-pub(crate) type GenericArg = chalk_ir::GenericArg<Interner>;
-pub(crate) type GenericArgData = chalk_ir::GenericArgData<Interner>;
-
-pub(crate) type Ty = chalk_ir::Ty<Interner>;
-pub type TyKind = chalk_ir::TyKind<Interner>;
-pub(crate) type TypeFlags = chalk_ir::TypeFlags;
-pub(crate) type DynTy = chalk_ir::DynTy<Interner>;
-pub(crate) type FnPointer = chalk_ir::FnPointer<Interner>;
-pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor
-
-pub type AliasTy = chalk_ir::AliasTy<Interner>;
-
-pub(crate) type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
-pub(crate) type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
-
-pub(crate) type Lifetime = chalk_ir::Lifetime<Interner>;
-pub(crate) type LifetimeData = chalk_ir::LifetimeData<Interner>;
-pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
-
-pub(crate) type ConstValue = chalk_ir::ConstValue<Interner>;
-
-pub(crate) type Const = chalk_ir::Const<Interner>;
-pub(crate) type ConstData = chalk_ir::ConstData<Interner>;
-pub(crate) type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
-
-pub(crate) type TraitRef = chalk_ir::TraitRef<Interner>;
-pub(crate) type QuantifiedWhereClause = Binders<WhereClause>;
-pub(crate) type Canonical<T> = chalk_ir::Canonical<T>;
-
-pub(crate) type ChalkTraitId = chalk_ir::TraitId<Interner>;
-pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
-
-pub(crate) type FnSig = chalk_ir::FnSig<Interner>;
-
-pub(crate) type InEnvironment<T> = chalk_ir::InEnvironment<T>;
-pub type AliasEq = chalk_ir::AliasEq<Interner>;
-pub type WhereClause = chalk_ir::WhereClause<Interner>;
-
-pub(crate) type DomainGoal = chalk_ir::DomainGoal<Interner>;
-pub(crate) type Goal = chalk_ir::Goal<Interner>;
-
-pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>;
-pub(crate) type GoalData = chalk_ir::GoalData<Interner>;
-pub(crate) type ProgramClause = chalk_ir::ProgramClause<Interner>;
/// A constant can have reference to other things. Memory map job is holding
/// the necessary bits of memory of the const eval session to keep the constant
@@ -229,7 +133,7 @@
}
impl<'db> MemoryMap<'db> {
- pub fn vtable_ty(&self, id: usize) -> Result<crate::next_solver::Ty<'db>, MirEvalError<'db>> {
+ pub fn vtable_ty(&self, id: usize) -> Result<Ty<'db>, MirEvalError<'db>> {
match self {
MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)),
MemoryMap::Complex(cm) => cm.vtable.ty(id),
@@ -279,118 +183,11 @@
}
}
-// FIXME(next-solver): add a lifetime to this
-/// A concrete constant value
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstScalar {
- Bytes(Box<[u8]>, MemoryMap<'static>),
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- UnevaluatedConst(GeneralConstId, Substitution),
- /// Case of an unknown value that rustc might know but we don't
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
- // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
- Unknown,
-}
-
-impl Hash for ConstScalar {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- core::mem::discriminant(self).hash(state);
- if let ConstScalar::Bytes(b, _) = self {
- b.hash(state)
- }
- }
-}
-
-/// A concrete constant value
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstScalarNs<'db> {
- Bytes(Box<[u8]>, MemoryMap<'db>),
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- UnevaluatedConst(GeneralConstId, Substitution),
- /// Case of an unknown value that rustc might know but we don't
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
- // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
- Unknown,
-}
-
-impl Hash for ConstScalarNs<'_> {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- core::mem::discriminant(self).hash(state);
- if let ConstScalarNs::Bytes(b, _) = self {
- b.hash(state)
- }
- }
-}
-
/// Return an index of a parameter in the generic type parameter list by it's id.
pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
generics::generics(db, id.parent).type_or_const_param_idx(id)
}
-pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
-where
- T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
-{
- Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
-}
-
-pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
- value: T,
-) -> Binders<T> {
- Binders::new(
- chalk_ir::VariableKinds::from_iter(
- Interner,
- std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
- ),
- value,
- )
-}
-
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
- db: &dyn HirDatabase,
- generics: &Generics,
- value: T,
-) -> Binders<T> {
- Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value)
-}
-
-pub(crate) fn variable_kinds_from_iter(
- db: &dyn HirDatabase,
- iter: impl Iterator<Item = hir_def::GenericParamId>,
-) -> VariableKinds<Interner> {
- VariableKinds::from_iter(
- Interner,
- iter.map(|x| match x {
- hir_def::GenericParamId::ConstParamId(id) => {
- chalk_ir::VariableKind::Const(db.const_param_ty(id))
- }
- hir_def::GenericParamId::TypeParamId(_) => {
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
- }
- hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
- }),
- )
-}
-
-// FIXME: get rid of this, just replace it by FnPointer
-/// A function signature as seen by type inference: Several parameter types and
-/// one return type.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct CallableSig {
- params_and_return: Arc<[Ty]>,
- is_varargs: bool,
- safety: Safety,
- abi: FnAbi,
-}
-
-has_interner!(CallableSig);
-
#[derive(Debug, Copy, Clone, Eq)]
pub enum FnAbi {
Aapcs,
@@ -534,195 +331,23 @@
}
}
-/// A polymorphic function signature.
-pub type PolyFnSig = Binders<CallableSig>;
-
-impl CallableSig {
- pub fn from_params_and_return(
- params: impl Iterator<Item = Ty>,
- ret: Ty,
- is_varargs: bool,
- safety: Safety,
- abi: FnAbi,
- ) -> CallableSig {
- let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1);
- params_and_return.extend(params);
- params_and_return.push(ret);
- CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
- }
-
- pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
- let callable_def = ToChalk::from_chalk(db, def);
- let interner = DbInterner::new_with(db, None, None);
- let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
- let sig = db.callable_item_signature(callable_def);
- sig.instantiate(interner, args).skip_binder().to_chalk(interner)
- }
- pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
- CallableSig {
- // FIXME: what to do about lifetime params? -> return PolyFnSig
- params_and_return: Arc::from_iter(
- fn_ptr
- .substitution
- .clone()
- .shifted_out_to(Interner, DebruijnIndex::ONE)
- .expect("unexpected lifetime vars in fn ptr")
- .0
- .as_slice(Interner)
- .iter()
- .map(|arg| arg.assert_ty_ref(Interner).clone()),
- ),
- is_varargs: fn_ptr.sig.variadic,
- safety: fn_ptr.sig.safety,
- abi: fn_ptr.sig.abi,
- }
- }
- pub fn from_fn_sig_and_header<'db>(
- interner: DbInterner<'db>,
- sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>,
- header: rustc_type_ir::FnHeader<DbInterner<'db>>,
- ) -> CallableSig {
- CallableSig {
- // FIXME: what to do about lifetime params? -> return PolyFnSig
- params_and_return: Arc::from_iter(
- sig.skip_binder()
- .inputs_and_output
- .iter()
- .map(|t| convert_ty_for_result(interner, t)),
- ),
- is_varargs: header.c_variadic,
- safety: match header.safety {
- next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
- next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
- },
- abi: header.abi,
- }
- }
-
- pub fn to_fn_ptr(&self) -> FnPointer {
- FnPointer {
- num_binders: 0,
- sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs },
- substitution: FnSubst(Substitution::from_iter(
- Interner,
- self.params_and_return.iter().cloned(),
- )),
- }
- }
-
- pub fn abi(&self) -> FnAbi {
- self.abi
- }
-
- pub fn params(&self) -> &[Ty] {
- &self.params_and_return[0..self.params_and_return.len() - 1]
- }
-
- pub fn ret(&self) -> &Ty {
- &self.params_and_return[self.params_and_return.len() - 1]
- }
-}
-
-impl TypeFoldable<Interner> for CallableSig {
- fn try_fold_with<E>(
- self,
- folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
- outer_binder: DebruijnIndex,
- ) -> Result<Self, E> {
- let vec = self.params_and_return.to_vec();
- let folded = vec.try_fold_with(folder, outer_binder)?;
- Ok(CallableSig {
- params_and_return: folded.into(),
- is_varargs: self.is_varargs,
- safety: self.safety,
- abi: self.abi,
- })
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub enum ImplTraitId {
- ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), // FIXME(next-solver): Should be crate::nextsolver::ImplTraitIdx.
- TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
- AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
-}
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTraits {
- pub(crate) impl_traits: Arena<ImplTrait>,
-}
-
-has_interner!(ImplTraits);
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTrait {
- pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
-}
-
-pub type ImplTraitIdx = Idx<ImplTrait>;
-
-pub fn static_lifetime() -> Lifetime {
- LifetimeData::Static.intern(Interner)
-}
-
-pub fn error_lifetime() -> Lifetime {
- LifetimeData::Error.intern(Interner)
-}
-
-pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
- t: T,
- for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
- for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
-) -> T {
- use chalk_ir::fold::TypeFolder;
-
- #[derive(chalk_derive::FallibleTypeFolder)]
- #[has_interner(Interner)]
- struct FreeVarFolder<
- F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
- F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
- >(F1, F2);
- impl<F1: FnMut(BoundVar, DebruijnIndex) -> Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const>
- TypeFolder<Interner> for FreeVarFolder<F1, F2>
- {
- fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
- self.0(bound_var, outer_binder)
- }
-
- fn fold_free_var_const(
- &mut self,
- ty: Ty,
- bound_var: BoundVar,
- outer_binder: DebruijnIndex,
- ) -> Const {
- self.1(ty, bound_var, outer_binder)
- }
- }
- t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
+pub enum ImplTraitId<'db> {
+ ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>),
+ TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>),
}
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
/// ensures there are no unbound variables or inference variables anywhere in
/// the `t`.
-pub fn replace_errors_with_variables<'db, T>(
- interner: DbInterner<'db>,
- t: &T,
-) -> crate::next_solver::Canonical<'db, T>
+pub fn replace_errors_with_variables<'db, T>(interner: DbInterner<'db>, t: &T) -> Canonical<'db, T>
where
T: rustc_type_ir::TypeFoldable<DbInterner<'db>> + Clone,
{
use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable};
struct ErrorReplacer<'db> {
interner: DbInterner<'db>,
- vars: Vec<crate::next_solver::CanonicalVarKind<'db>>,
+ vars: Vec<CanonicalVarKind<'db>>,
binder: rustc_type_ir::DebruijnIndex,
}
impl<'db> FallibleTypeFolder<DbInterner<'db>> for ErrorReplacer<'db> {
@@ -735,10 +360,7 @@
self.interner
}
- fn try_fold_binder<T>(
- &mut self,
- t: crate::next_solver::Binder<'db, T>,
- ) -> Result<crate::next_solver::Binder<'db, T>, Self::Error>
+ fn try_fold_binder<T>(&mut self, t: Binder<'db, T>) -> Result<Binder<'db, T>, Self::Error>
where
T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
{
@@ -748,10 +370,7 @@
result
}
- fn try_fold_ty(
- &mut self,
- t: crate::next_solver::Ty<'db>,
- ) -> Result<crate::next_solver::Ty<'db>, Self::Error> {
+ fn try_fold_ty(&mut self, t: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
if !t.has_type_flags(
rustc_type_ir::TypeFlags::HAS_ERROR
| rustc_type_ir::TypeFlags::HAS_TY_INFER
@@ -764,34 +383,28 @@
#[cfg(debug_assertions)]
let error = || Err(());
#[cfg(not(debug_assertions))]
- let error = || Ok(crate::next_solver::Ty::new_error(self.interner, ErrorGuaranteed));
+ let error = || Ok(Ty::new_error(self.interner, crate::next_solver::ErrorGuaranteed));
match t.kind() {
- crate::next_solver::TyKind::Error(_) => {
+ TyKind::Error(_) => {
let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
- self.vars.push(crate::next_solver::CanonicalVarKind::Ty {
+ self.vars.push(CanonicalVarKind::Ty {
ui: rustc_type_ir::UniverseIndex::ZERO,
sub_root: var,
});
- Ok(crate::next_solver::Ty::new_bound(
+ Ok(Ty::new_bound(
self.interner,
self.binder,
- crate::next_solver::BoundTy {
- var,
- kind: crate::next_solver::BoundTyKind::Anon,
- },
+ BoundTy { var, kind: BoundTyKind::Anon },
))
}
- crate::next_solver::TyKind::Infer(_) => error(),
- crate::next_solver::TyKind::Bound(index, _) if index > self.binder => error(),
+ TyKind::Infer(_) => error(),
+ TyKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => error(),
_ => t.try_super_fold_with(self),
}
}
- fn try_fold_const(
- &mut self,
- ct: crate::next_solver::Const<'db>,
- ) -> Result<crate::next_solver::Const<'db>, Self::Error> {
+ fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
if !ct.has_type_flags(
rustc_type_ir::TypeFlags::HAS_ERROR
| rustc_type_ir::TypeFlags::HAS_TY_INFER
@@ -804,52 +417,42 @@
#[cfg(debug_assertions)]
let error = || Err(());
#[cfg(not(debug_assertions))]
- let error = || Ok(crate::next_solver::Const::error(self.interner));
+ let error = || Ok(Const::error(self.interner));
match ct.kind() {
- crate::next_solver::ConstKind::Error(_) => {
+ ConstKind::Error(_) => {
let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
- self.vars.push(crate::next_solver::CanonicalVarKind::Const(
- rustc_type_ir::UniverseIndex::ZERO,
- ));
- Ok(crate::next_solver::Const::new_bound(
- self.interner,
- self.binder,
- crate::next_solver::BoundConst { var },
- ))
+ self.vars.push(CanonicalVarKind::Const(rustc_type_ir::UniverseIndex::ZERO));
+ Ok(Const::new_bound(self.interner, self.binder, BoundConst { var }))
}
- crate::next_solver::ConstKind::Infer(_) => error(),
- crate::next_solver::ConstKind::Bound(index, _) if index > self.binder => error(),
+ ConstKind::Infer(_) => error(),
+ ConstKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+ error()
+ }
_ => ct.try_super_fold_with(self),
}
}
- fn try_fold_region(
- &mut self,
- region: crate::next_solver::Region<'db>,
- ) -> Result<crate::next_solver::Region<'db>, Self::Error> {
+ fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
#[cfg(debug_assertions)]
let error = || Err(());
#[cfg(not(debug_assertions))]
- let error = || Ok(crate::next_solver::Region::error(self.interner));
+ let error = || Ok(Region::error(self.interner));
match region.kind() {
- crate::next_solver::RegionKind::ReError(_) => {
+ RegionKind::ReError(_) => {
let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
- self.vars.push(crate::next_solver::CanonicalVarKind::Region(
- rustc_type_ir::UniverseIndex::ZERO,
- ));
- Ok(crate::next_solver::Region::new_bound(
+ self.vars.push(CanonicalVarKind::Region(rustc_type_ir::UniverseIndex::ZERO));
+ Ok(Region::new_bound(
self.interner,
self.binder,
- crate::next_solver::BoundRegion {
- var,
- kind: crate::next_solver::BoundRegionKind::Anon,
- },
+ BoundRegion { var, kind: BoundRegionKind::Anon },
))
}
- crate::next_solver::RegionKind::ReVar(_) => error(),
- crate::next_solver::RegionKind::ReBound(index, _) if index > self.binder => error(),
+ RegionKind::ReVar(_) => error(),
+ RegionKind::ReBound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+ error()
+ }
_ => Ok(region),
}
}
@@ -861,18 +464,18 @@
Ok(t) => t,
Err(_) => panic!("Encountered unbound or inference vars in {t:?}"),
};
- crate::next_solver::Canonical {
+ Canonical {
value,
max_universe: rustc_type_ir::UniverseIndex::ZERO,
- variables: crate::next_solver::CanonicalVars::new_from_iter(interner, error_replacer.vars),
+ variables: CanonicalVars::new_from_iter(interner, error_replacer.vars),
}
}
pub fn callable_sig_from_fn_trait<'db>(
- self_ty: crate::next_solver::Ty<'db>,
+ self_ty: Ty<'db>,
trait_env: Arc<TraitEnvironment<'db>>,
db: &'db dyn HirDatabase,
-) -> Option<(FnTrait, crate::next_solver::PolyFnSig<'db>)> {
+) -> Option<(FnTrait, PolyFnSig<'db>)> {
let krate = trait_env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
let output_assoc_type = fn_once_trait
@@ -880,54 +483,46 @@
.associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
let mut table = InferenceTable::new(db, trait_env.clone());
- let b = TyBuilder::trait_ref(db, fn_once_trait);
- if b.remaining() != 2 {
- return None;
- }
// Register two obligations:
// - Self: FnOnce<?args_ty>
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
let args_ty = table.next_ty_var();
let args = [self_ty, args_ty];
- let trait_ref = crate::next_solver::TraitRef::new(table.interner(), fn_once_trait.into(), args);
- let projection = crate::next_solver::Ty::new_alias(
+ let trait_ref = TraitRef::new(table.interner(), fn_once_trait.into(), args);
+ let projection = Ty::new_alias(
table.interner(),
rustc_type_ir::AliasTyKind::Projection,
- crate::next_solver::AliasTy::new(table.interner(), output_assoc_type.into(), args),
+ AliasTy::new(table.interner(), output_assoc_type.into(), args),
);
- let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner());
+ let pred = Predicate::upcast_from(trait_ref, table.interner());
if !table.try_obligation(pred).no_solution() {
table.register_obligation(pred);
let return_ty = table.normalize_alias_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
let fn_x_trait = fn_x.get_id(db, krate)?;
- let trait_ref =
- crate::next_solver::TraitRef::new(table.interner(), fn_x_trait.into(), args);
+ let trait_ref = TraitRef::new(table.interner(), fn_x_trait.into(), args);
if !table
- .try_obligation(crate::next_solver::Predicate::upcast_from(
- trait_ref,
- table.interner(),
- ))
+ .try_obligation(Predicate::upcast_from(trait_ref, table.interner()))
.no_solution()
{
let ret_ty = table.resolve_completely(return_ty);
let args_ty = table.resolve_completely(args_ty);
- let crate::next_solver::TyKind::Tuple(params) = args_ty.kind() else {
+ let TyKind::Tuple(params) = args_ty.kind() else {
return None;
};
- let inputs_and_output = crate::next_solver::Tys::new_from_iter(
+ let inputs_and_output = Tys::new_from_iter(
table.interner(),
params.iter().chain(std::iter::once(ret_ty)),
);
return Some((
fn_x,
- crate::next_solver::Binder::dummy(crate::next_solver::FnSig {
+ Binder::dummy(FnSig {
inputs_and_output,
c_variadic: false,
- safety: crate::next_solver::abi::Safety::Safe,
+ safety: abi::Safety::Safe,
abi: FnAbi::RustCall,
}),
));
@@ -946,16 +541,16 @@
impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for ParamCollector {
type Result = ();
- fn visit_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> Self::Result {
- if let crate::next_solver::TyKind::Param(param) = ty.kind() {
+ fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
+ if let TyKind::Param(param) = ty.kind() {
self.params.insert(param.id.into());
}
ty.super_visit_with(self);
}
- fn visit_const(&mut self, konst: crate::next_solver::Const<'db>) -> Self::Result {
- if let crate::next_solver::ConstKind::Param(param) = konst.kind() {
+ fn visit_const(&mut self, konst: Const<'db>) -> Self::Result {
+ if let ConstKind::Param(param) = konst.kind() {
self.params.insert(param.id.into());
}
@@ -974,7 +569,7 @@
}
pub fn known_const_to_ast<'db>(
- konst: crate::next_solver::Const<'db>,
+ konst: Const<'db>,
db: &'db dyn HirDatabase,
display_target: DisplayTarget,
) -> Option<ConstArg> {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index b18d713..a181ae0 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -11,82 +11,93 @@
use std::{
cell::OnceCell,
iter, mem,
- ops::{self, Not as _},
+ ops::{self, Deref, Not as _},
};
use base_db::Crate;
-use chalk_ir::{
- Mutability, Safety, TypeOutlives,
- cast::Cast,
- fold::{Shift, TypeFoldable},
- interner::HasInterner,
-};
-
use either::Either;
use hir_def::{
- AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
- GenericParamId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId,
+ AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
+ FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+ LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeParamId,
UnionId, VariantId,
builtin_type::BuiltinType,
- expr_store::{ExpressionStore, path::Path},
- hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate},
+ expr_store::{ExpressionStore, HygieneId, path::Path},
+ hir::generics::{
+ GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
+ },
+ item_tree::FieldsShape,
lang_item::LangItem,
- resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
- signatures::TraitFlags,
+ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
+ signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
type_ref::{
- ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef,
- TypeRefId,
+ ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
+ TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
},
};
use hir_expand::name::Name;
-use la_arena::{Arena, ArenaMap};
+use la_arena::{Arena, ArenaMap, Idx};
+use path::{PathDiagnosticCallback, PathLoweringContext};
+use rustc_ast_ir::Mutability;
use rustc_hash::FxHashSet;
+use rustc_pattern_analysis::Captures;
+use rustc_type_ir::{
+ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate,
+ ExistentialProjection, ExistentialTraitRef, FnSig, OutlivesPredicate,
+ TyKind::{self},
+ TypeVisitableExt,
+ inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _},
+};
+use salsa::plumbing::AsId;
+use smallvec::{SmallVec, smallvec};
use stdx::{impl_from, never};
use triomphe::{Arc, ThinArc};
use crate::{
- AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst,
- ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives,
- QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty,
- TyBuilder, TyKind, WhereClause, all_super_traits,
- consteval_chalk::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
+ FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+ consteval::intern_const_ref,
db::HirDatabase,
- error_lifetime,
generics::{Generics, generics, trait_self_param_idx},
- lower::{
- diagnostics::*,
- path::{PathDiagnosticCallback, PathLoweringContext},
- },
- make_binders,
- mapping::{from_chalk_trait_id, lt_to_placeholder_idx},
next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, NextSolverToChalk},
+ AliasTy, Binder, BoundExistentialPredicates, Clause, Clauses, Const, DbInterner,
+ EarlyBinder, EarlyParamRegion, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst,
+ ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
+ UnevaluatedConst, abi::Safety,
},
- static_lifetime, to_chalk_trait_id, to_placeholder_idx,
- utils::all_super_trait_refs,
- variable_kinds_from_iter,
};
+pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTraits<'db> {
+ pub(crate) impl_traits: Arena<ImplTrait<'db>>,
+}
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTrait<'db> {
+ pub(crate) predicates: Vec<Clause<'db>>,
+}
+
+pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>;
+
#[derive(Debug, Default)]
-struct ImplTraitLoweringState {
+struct ImplTraitLoweringState<'db> {
/// When turning `impl Trait` into opaque types, we have to collect the
/// bounds at the same time to get the IDs correct (without becoming too
/// complicated).
mode: ImplTraitLoweringMode,
// This is structured as a struct with fields and not as an enum because it helps with the borrow checker.
- opaque_type_data: Arena<ImplTrait>,
+ opaque_type_data: Arena<ImplTrait<'db>>,
}
-impl ImplTraitLoweringState {
- fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState {
+
+impl<'db> ImplTraitLoweringState<'db> {
+ fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> {
Self { mode, opaque_type_data: Arena::new() }
}
}
-pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
-
#[derive(Debug, Clone)]
-pub(crate) enum LifetimeElisionKind {
+pub enum LifetimeElisionKind<'db> {
/// Create a new anonymous lifetime parameter and reference it.
///
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
@@ -104,75 +115,109 @@
AnonymousCreateParameter { report_in_path: bool },
/// Replace all anonymous lifetimes by provided lifetime.
- Elided(Lifetime),
+ Elided(Region<'db>),
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
/// error on default object bounds (e.g., `Box<dyn Foo>`).
AnonymousReportError,
+ /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
+ /// otherwise give a warning that the previous behavior of introducing a new early-bound
+ /// lifetime is a bug and will be removed (if `only_lint` is enabled).
+ StaticIfNoLifetimeInScope { only_lint: bool },
+
+ /// Signal we cannot find which should be the anonymous lifetime.
+ ElisionFailure,
+
/// Infer all elided lifetimes.
Infer,
}
-impl LifetimeElisionKind {
+impl<'db> LifetimeElisionKind<'db> {
#[inline]
- pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
+ pub(crate) fn for_const(
+ interner: DbInterner<'db>,
+ const_parent: ItemContainerId,
+ ) -> LifetimeElisionKind<'db> {
+ match const_parent {
+ ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
+ LifetimeElisionKind::Elided(Region::new_static(interner))
+ }
+ ItemContainerId::ImplId(_) => {
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
+ }
+ ItemContainerId::TraitId(_) => {
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false }
+ }
+ }
+ }
+
+ #[inline]
+ pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> {
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
+ }
+
+ #[inline]
+ pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> {
// FIXME: We should use the elided lifetime here, or `ElisionFailure`.
- LifetimeElisionKind::Elided(error_lifetime())
+ LifetimeElisionKind::Elided(Region::error(interner))
}
}
#[derive(Debug)]
-pub(crate) struct TyLoweringContext<'db> {
+pub struct TyLoweringContext<'db, 'a> {
pub db: &'db dyn HirDatabase,
- resolver: &'db Resolver<'db>,
- store: &'db ExpressionStore,
+ interner: DbInterner<'db>,
+ resolver: &'a Resolver<'db>,
+ store: &'a ExpressionStore,
def: GenericDefId,
generics: OnceCell<Generics>,
in_binders: DebruijnIndex,
- /// Note: Conceptually, it's thinkable that we could be in a location where
- /// some type params should be represented as placeholders, and others
- /// should be converted to variables. I think in practice, this isn't
- /// possible currently, so this should be fine for now.
- pub type_param_mode: ParamLoweringMode,
- impl_trait_mode: ImplTraitLoweringState,
+ impl_trait_mode: ImplTraitLoweringState<'db>,
/// Tracks types with explicit `?Sized` bounds.
- pub(crate) unsized_types: FxHashSet<Ty>,
+ pub(crate) unsized_types: FxHashSet<Ty<'db>>,
pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
- lifetime_elision: LifetimeElisionKind,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ /// When lowering the defaults for generic params, this contains the index of the currently lowered param.
+ /// We disallow referring to later params, or to ADT's `Self`.
+ lowering_param_default: Option<u32>,
}
-impl<'db> TyLoweringContext<'db> {
- pub(crate) fn new(
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
+ pub fn new(
db: &'db dyn HirDatabase,
- resolver: &'db Resolver<'db>,
- store: &'db ExpressionStore,
+ resolver: &'a Resolver<'db>,
+ store: &'a ExpressionStore,
def: GenericDefId,
- lifetime_elision: LifetimeElisionKind,
+ lifetime_elision: LifetimeElisionKind<'db>,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
- let type_param_mode = ParamLoweringMode::Placeholder;
- let in_binders = DebruijnIndex::INNERMOST;
+ let in_binders = DebruijnIndex::ZERO;
Self {
db,
+ interner: DbInterner::new_with(db, Some(resolver.krate()), None),
resolver,
def,
generics: Default::default(),
store,
in_binders,
impl_trait_mode,
- type_param_mode,
unsized_types: FxHashSet::default(),
diagnostics: Vec::new(),
lifetime_elision,
+ lowering_param_default: None,
}
}
+ pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) {
+ self.lifetime_elision = lifetime_elision;
+ }
+
pub(crate) fn with_debruijn<T>(
&mut self,
debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+ f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
) -> T {
let old_debruijn = mem::replace(&mut self.in_binders, debruijn);
let result = f(self);
@@ -183,28 +228,22 @@
pub(crate) fn with_shifted_in<T>(
&mut self,
debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+ f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
) -> T {
- self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
- }
-
- fn with_lifetime_elision<T>(
- &mut self,
- lifetime_elision: LifetimeElisionKind,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
- ) -> T {
- let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision);
- let result = f(self);
- self.lifetime_elision = old_lifetime_elision;
- result
+ self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f)
}
pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
}
- pub(crate) fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
- Self { type_param_mode, ..self }
+ pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+ self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
+ self
+ }
+
+ pub(crate) fn lowering_param_default(&mut self, index: u32) {
+ self.lowering_param_default = Some(index);
}
pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
@@ -213,7 +252,7 @@
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub enum ImplTraitLoweringMode {
+pub(crate) enum ImplTraitLoweringMode {
/// `impl Trait` gets lowered into an opaque type that doesn't unify with
/// anything except itself. This is used in places where values flow 'out',
/// i.e. for arguments of the function we're currently checking, and return
@@ -224,30 +263,17 @@
Disallowed,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ParamLoweringMode {
- Placeholder,
- Variable,
-}
-
-impl<'db> TyLoweringContext<'db> {
- pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty {
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
+ pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
self.lower_ty_ext(type_ref).0
}
- pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const {
+ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
let const_ref = &self.store[const_ref.expr];
match const_ref {
- hir_def::hir::Expr::Path(path) => path_to_const(
- self.db,
- self.resolver,
- path,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- const_type.clone(),
- )
- .unwrap_or_else(|| unknown_const(const_type)),
+ hir_def::hir::Expr::Path(path) => {
+ self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
+ }
hir_def::hir::Expr::Literal(literal) => intern_const_ref(
self.db,
&match *literal {
@@ -290,32 +316,88 @@
}
}
- pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const {
- path_to_const(
- self.db,
- self.resolver,
- path,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- const_type.clone(),
- )
- .unwrap_or_else(|| unknown_const(const_type))
+ pub(crate) fn path_to_const(&mut self, path: &Path) -> Option<Const<'db>> {
+ match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) {
+ Some(ValueNs::GenericParam(p)) => {
+ let args = self.generics();
+ match args.type_or_const_param_idx(p.into()) {
+ Some(idx) => Some(self.const_param(p, idx as u32)),
+ None => {
+ never!(
+ "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
+ args,
+ path,
+ p
+ );
+ None
+ }
+ }
+ }
+ Some(ValueNs::ConstId(c)) => {
+ let args = GenericArgs::new_from_iter(self.interner, []);
+ Some(Const::new(
+ self.interner,
+ rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
+ SolverDefId::ConstId(c),
+ args,
+ )),
+ ))
+ }
+ _ => None,
+ }
+ }
+
+ pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> {
+ self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
}
fn generics(&self) -> &Generics {
self.generics.get_or_init(|| generics(self.db, self.def))
}
- pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
+ fn param_index_is_disallowed(&self, index: u32) -> bool {
+ self.lowering_param_default
+ .is_some_and(|disallow_params_after| index >= disallow_params_after)
+ }
+
+ fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Ty::new_error(self.interner, ErrorGuaranteed)
+ } else {
+ Ty::new_param(self.interner, id, index)
+ }
+ }
+
+ fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Const::error(self.interner)
+ } else {
+ Const::new_param(self.interner, ParamConst { id, index })
+ }
+ }
+
+ fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Region::error(self.interner)
+ } else {
+ Region::new_early_param(self.interner, EarlyParamRegion { id, index })
+ }
+ }
+
+ #[tracing::instrument(skip(self), ret)]
+ pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) {
+ let interner = self.interner;
let mut res = None;
let type_ref = &self.store[type_ref_id];
+ tracing::debug!(?type_ref);
let ty = match type_ref {
- TypeRef::Never => TyKind::Never.intern(Interner),
+ TypeRef::Never => Ty::new(interner, TyKind::Never),
TypeRef::Tuple(inner) => {
let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
- TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
- .intern(Interner)
+ Ty::new_tup_from_iter(interner, inner_tys)
}
TypeRef::Path(path) => {
let (ty, res_) =
@@ -325,81 +407,61 @@
}
&TypeRef::TypeParam(type_param_id) => {
res = Some(TypeNs::GenericParam(type_param_id));
- match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- let generics = self.generics();
- let idx = generics.type_or_const_param_idx(type_param_id.into()).unwrap();
- TyKind::Placeholder(to_placeholder_idx(
- self.db,
- type_param_id.into(),
- idx as u32,
- ))
- }
- ParamLoweringMode::Variable => {
- let idx =
- self.generics().type_or_const_param_idx(type_param_id.into()).unwrap();
- TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
- }
- }
- .intern(Interner)
+
+ let generics = self.generics();
+ let (idx, _data) =
+ generics.type_or_const_param(type_param_id.into()).expect("matching generics");
+ self.type_param(type_param_id, idx as u32)
}
&TypeRef::RawPtr(inner, mutability) => {
let inner_ty = self.lower_ty(inner);
- TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
+ Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability)))
}
TypeRef::Array(array) => {
let inner_ty = self.lower_ty(array.ty);
- let const_len = self.lower_const(&array.len, TyBuilder::usize());
- TyKind::Array(inner_ty, const_len).intern(Interner)
+ let const_len = self.lower_const(array.len, Ty::new_usize(interner));
+ Ty::new_array_with_const_len(interner, inner_ty, const_len)
}
&TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner);
- TyKind::Slice(inner_ty).intern(Interner)
+ Ty::new_slice(interner, inner_ty)
}
TypeRef::Reference(ref_) => {
let inner_ty = self.lower_ty(ref_.ty);
- // FIXME: It should infer the eldided lifetimes instead of stubbing with static
+ // FIXME: It should infer the eldided lifetimes instead of stubbing with error
let lifetime = ref_
.lifetime
- .as_ref()
- .map_or_else(error_lifetime, |&lr| self.lower_lifetime(lr));
- TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
- .intern(Interner)
+ .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
+ Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
}
- TypeRef::Placeholder => TyKind::Error.intern(Interner),
+ TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
TypeRef::Fn(fn_) => {
- let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- let (params, ret) = fn_.split_params_and_ret();
- let mut subst = Vec::with_capacity(fn_.params.len());
- ctx.with_lifetime_elision(
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false },
- |ctx| {
- subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr)));
- },
- );
- ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| {
- subst.push(ctx.lower_ty(ret));
- });
- Substitution::from_iter(Interner, subst)
- });
- TyKind::Function(FnPointer {
- num_binders: 0, // FIXME lower `for<'a> fn()` correctly
- sig: FnSig {
+ let substs = self.with_shifted_in(
+ DebruijnIndex::from_u32(1),
+ |ctx: &mut TyLoweringContext<'_, '_>| {
+ Tys::new_from_iter(
+ interner,
+ fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+ )
+ },
+ );
+ Ty::new_fn_ptr(
+ interner,
+ Binder::dummy(FnSig {
abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
- variadic: fn_.is_varargs,
- },
- substitution: FnSubst(substs),
- })
- .intern(Interner)
+ c_variadic: fn_.is_varargs,
+ inputs_and_output: substs,
+ }),
+ )
}
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
match self.impl_trait_mode.mode {
ImplTraitLoweringMode::Opaque => {
- let origin = match self.def {
- GenericDefId::FunctionId(it) => Either::Left(it),
- GenericDefId::TypeAliasId(it) => Either::Right(it),
+ let origin = match self.resolver.generic_def() {
+ Some(GenericDefId::FunctionId(it)) => Either::Left(it),
+ Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
_ => panic!(
"opaque impl trait lowering must be in function or type alias"
),
@@ -408,9 +470,18 @@
// this dance is to make sure the data is in the right
// place even if we encounter more opaque types while
// lowering the bounds
- let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait {
- bounds: crate::make_single_type_binders(Vec::default()),
- });
+ let idx = self
+ .impl_trait_mode
+ .opaque_type_data
+ .alloc(ImplTrait { predicates: Vec::default() });
+
+ let impl_trait_id = origin.either(
+ |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
+ |a| ImplTraitId::TypeAliasImplTrait(a, idx),
+ );
+ let opaque_ty_id: SolverDefId =
+ self.db.intern_impl_trait_id(impl_trait_id).into();
+
// We don't want to lower the bounds inside the binders
// we're currently in, because they don't end up inside
// those binders. E.g. when we have `impl Trait<impl
@@ -421,27 +492,25 @@
// parameter of the outer function, it's just one binder
// away instead of two.
let actual_opaque_type_data = self
- .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
- ctx.lower_impl_trait(bounds, self.resolver.krate())
+ .with_debruijn(DebruijnIndex::ZERO, |ctx| {
+ ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate())
});
self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data;
- let impl_trait_id = origin.either(
- |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
- |a| ImplTraitId::TypeAliasImplTrait(a, idx),
- );
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- let generics = generics(self.db, origin.either(|f| f.into(), |a| a.into()));
- let parameters = generics.bound_vars_subst(self.db, self.in_binders);
- TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
+ let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id);
+ Ty::new_alias(
+ self.interner,
+ AliasTyKind::Opaque,
+ AliasTy::new_from_args(self.interner, opaque_ty_id, args),
+ )
}
ImplTraitLoweringMode::Disallowed => {
// FIXME: report error
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.interner, ErrorGuaranteed)
}
}
}
- TypeRef::Error => TyKind::Error.intern(Interner),
+ TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
};
(ty, res)
}
@@ -449,8 +518,8 @@
/// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which.
- fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option<TypeOrConstParamId> {
- let type_ref = &self.store[type_ref_id];
+ fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+ let type_ref = &self.store[type_ref];
let path = match type_ref {
TypeRef::Path(path) => path,
&TypeRef::TypeParam(idx) => return Some(idx.into()),
@@ -462,9 +531,8 @@
if path.segments().len() > 1 {
return None;
}
- let mut ctx = self.at_path(PathId::from_type_ref_unchecked(type_ref_id));
- let resolution = match ctx.resolve_path_in_type_ns() {
- Some((it, None)) => it,
+ let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) {
+ Some((it, None, _)) => it,
_ => return None,
};
match resolution {
@@ -474,7 +542,7 @@
}
#[inline]
- fn on_path_diagnostic_callback<'a>(type_ref: TypeRefId) -> PathDiagnosticCallback<'a, 'db> {
+ fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> {
PathDiagnosticCallback {
data: Either::Left(PathDiagnosticCallbackData(type_ref)),
callback: |data, this, diag| {
@@ -485,7 +553,7 @@
}
#[inline]
- fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'db> {
+ fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> {
PathLoweringContext::new(
self,
Self::on_path_diagnostic_callback(path_id.type_ref()),
@@ -493,7 +561,7 @@
)
}
- pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
+ pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option<TypeNs>) {
// Resolve the path (in type namespace)
if let Some(type_ref) = path.type_anchor() {
let (ty, res) = self.lower_ty_ext(type_ref);
@@ -504,7 +572,7 @@
let mut ctx = self.at_path(path_id);
let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
Some(it) => it,
- None => return (TyKind::Error.intern(Interner), None),
+ None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
};
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
@@ -520,8 +588,8 @@
fn lower_trait_ref_from_path(
&mut self,
path_id: PathId,
- explicit_self_ty: Ty,
- ) -> Option<(TraitRef, PathLoweringContext<'_, 'db>)> {
+ explicit_self_ty: Ty<'db>,
+ ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> {
let mut ctx = self.at_path(path_id);
let resolved = match ctx.resolve_path_in_type_ns_fully()? {
// FIXME(trait_alias): We need to handle trait alias here.
@@ -531,26 +599,57 @@
Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
}
- /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
- /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
- /// **parent**. This is important so we generate the correct bound var/placeholder.
+ fn lower_trait_ref(
+ &mut self,
+ trait_ref: &HirTraitRef,
+ explicit_self_ty: Ty<'db>,
+ ) -> Option<TraitRef<'db>> {
+ self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
+ }
+
pub(crate) fn lower_where_predicate<'b>(
&'b mut self,
where_predicate: &'b WherePredicate,
ignore_bindings: bool,
- ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'db, 'b> {
+ generics: &Generics,
+ predicate_filter: PredicateFilter,
+ ) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
match where_predicate {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
+ if let PredicateFilter::SelfTrait = predicate_filter {
+ let target_type = &self.store[*target];
+ let self_type = 'is_self: {
+ if let TypeRef::Path(path) = target_type
+ && path.is_self_type()
+ {
+ break 'is_self true;
+ }
+ if let TypeRef::TypeParam(param) = target_type
+ && generics[param.local_id()].is_trait_self()
+ {
+ break 'is_self true;
+ }
+ false
+ };
+ if !self_type {
+ return Either::Left(Either::Left(iter::empty()));
+ }
+ }
let self_ty = self.lower_ty(*target);
- Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings))
+ Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
}
- &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(
- crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives {
- a: self.lower_lifetime(bound),
- b: self.lower_lifetime(target),
- })),
- )),
+ &WherePredicate::Lifetime { bound, target } => {
+ Either::Right(iter::once(Clause(Predicate::new(
+ self.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
+ self.lower_lifetime(bound),
+ self.lower_lifetime(target),
+ )),
+ )),
+ ))))
+ }
}
.into_iter()
}
@@ -558,40 +657,40 @@
pub(crate) fn lower_type_bound<'b>(
&'b mut self,
bound: &'b TypeBound,
- self_ty: Ty,
+ self_ty: Ty<'db>,
ignore_bindings: bool,
- ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'db> {
+ ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
+ let interner = self.interner;
let mut assoc_bounds = None;
let mut clause = None;
match bound {
&TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
// FIXME Don't silently drop the hrtb lifetimes here
- if let Some((trait_ref, mut ctx)) =
- self.lower_trait_ref_from_path(path, self_ty.clone())
- {
+ if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
// FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
// sized-hierarchy correctly.
let meta_sized = LangItem::MetaSized
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
let pointee_sized = LangItem::PointeeSized
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let destruct = LangItem::Destruct
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let hir_trait_id = trait_ref.hir_trait_id();
- if meta_sized.is_some_and(|it| it == hir_trait_id)
- || destruct.is_some_and(|it| it == hir_trait_id)
- {
+ if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) {
// Ignore this bound
- } else if pointee_sized.is_some_and(|it| it == hir_trait_id) {
+ } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) {
// Regard this as `?Sized` bound
ctx.ty_ctx().unsized_types.insert(self_ty);
} else {
if !ignore_bindings {
- assoc_bounds =
- ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
+ assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
}
- clause =
- Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
+ clause = Some(Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ )));
}
}
}
@@ -601,95 +700,137 @@
// `?Sized` has no of them.
// If we got another trait here ignore the bound completely.
let trait_id = self
- .lower_trait_ref_from_path(path, self_ty.clone())
- .map(|(trait_ref, _)| trait_ref.hir_trait_id());
+ .lower_trait_ref_from_path(path, self_ty)
+ .map(|(trait_ref, _)| trait_ref.def_id.0);
if trait_id == sized_trait {
self.unsized_types.insert(self_ty);
}
}
&TypeBound::Lifetime(l) => {
let lifetime = self.lower_lifetime(l);
- clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
- ty: self_ty,
- lifetime,
- })));
+ clause = Some(Clause(Predicate::new(
+ self.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate(
+ self_ty, lifetime,
+ )),
+ )),
+ )));
}
TypeBound::Use(_) | TypeBound::Error => {}
}
clause.into_iter().chain(assoc_bounds.into_iter().flatten())
}
- fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty {
- let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
+ fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
+ let interner = self.interner;
+ // FIXME: we should never create non-existential predicates in the first place
+ // For now, use an error type so we don't run into dummy binder issues
+ let self_ty = Ty::new_error(interner, ErrorGuaranteed);
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
// order but should be in the same order for the same set but possibly different order of
// bounds in the input.
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
let mut lifetime = None;
- let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- let mut lowered_bounds = Vec::new();
+ let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
+ let mut lowered_bounds: Vec<
+ rustc_type_ir::Binder<DbInterner<'db>, ExistentialPredicate<DbInterner<'db>>>,
+ > = Vec::new();
for b in bounds {
- ctx.lower_type_bound(b, self_ty.clone(), false).for_each(|b| {
- let filter = match b.skip_binders() {
- WhereClause::Implemented(_) | WhereClause::AliasEq(_) => true,
- WhereClause::LifetimeOutlives(_) => false,
- WhereClause::TypeOutlives(t) => {
- lifetime = Some(t.lifetime.clone());
- false
- }
- };
- if filter {
- lowered_bounds.push(b);
+ let db = ctx.db;
+ ctx.lower_type_bound(b, self_ty, false).for_each(|b| {
+ if let Some(bound) = b
+ .kind()
+ .map_bound(|c| match c {
+ rustc_type_ir::ClauseKind::Trait(t) => {
+ let id = t.def_id();
+ let is_auto =
+ db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+ if is_auto {
+ Some(ExistentialPredicate::AutoTrait(t.def_id()))
+ } else {
+ Some(ExistentialPredicate::Trait(
+ ExistentialTraitRef::new_from_args(
+ interner,
+ t.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ t.trait_ref.args.iter().skip(1),
+ ),
+ ),
+ ))
+ }
+ }
+ rustc_type_ir::ClauseKind::Projection(p) => {
+ Some(ExistentialPredicate::Projection(
+ ExistentialProjection::new_from_args(
+ interner,
+ p.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ p.projection_term.args.iter().skip(1),
+ ),
+ p.term,
+ ),
+ ))
+ }
+ rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => {
+ lifetime = Some(outlives_predicate.1);
+ None
+ }
+ rustc_type_ir::ClauseKind::RegionOutlives(_)
+ | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+ | rustc_type_ir::ClauseKind::WellFormed(_)
+ | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+ | rustc_type_ir::ClauseKind::HostEffect(_)
+ | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+ })
+ .transpose()
+ {
+ lowered_bounds.push(bound);
}
- });
+ })
}
let mut multiple_regular_traits = false;
let mut multiple_same_projection = false;
lowered_bounds.sort_unstable_by(|lhs, rhs| {
use std::cmp::Ordering;
- match (lhs.skip_binders(), rhs.skip_binders()) {
- (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
- let lhs_id = lhs.trait_id;
- let lhs_is_auto = ctx
- .db
- .trait_signature(from_chalk_trait_id(lhs_id))
- .flags
- .contains(TraitFlags::AUTO);
- let rhs_id = rhs.trait_id;
- let rhs_is_auto = ctx
- .db
- .trait_signature(from_chalk_trait_id(rhs_id))
- .flags
- .contains(TraitFlags::AUTO);
-
- if !lhs_is_auto && !rhs_is_auto {
- multiple_regular_traits = true;
- }
- // Note that the ordering here is important; this ensures the invariant
- // mentioned above.
- (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
+ match ((*lhs).skip_binder(), (*rhs).skip_binder()) {
+ (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => {
+ multiple_regular_traits = true;
+ // Order doesn't matter - we error
+ Ordering::Equal
}
- (WhereClause::Implemented(_), _) => Ordering::Less,
- (_, WhereClause::Implemented(_)) => Ordering::Greater,
- (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
- match (&lhs.alias, &rhs.alias) {
- (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
- // We only compare the `associated_ty_id`s. We shouldn't have
- // multiple bounds for an associated type in the correct Rust code,
- // and if we do, we error out.
- if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
- multiple_same_projection = true;
- }
- lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
- }
- // We don't produce `AliasTy::Opaque`s yet.
+ (
+ ExistentialPredicate::AutoTrait(lhs_id),
+ ExistentialPredicate::AutoTrait(rhs_id),
+ ) => lhs_id.0.cmp(&rhs_id.0),
+ (ExistentialPredicate::Trait(_), _) => Ordering::Less,
+ (_, ExistentialPredicate::Trait(_)) => Ordering::Greater,
+ (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less,
+ (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater,
+ (
+ ExistentialPredicate::Projection(lhs),
+ ExistentialPredicate::Projection(rhs),
+ ) => {
+ let lhs_id = match lhs.def_id {
+ SolverDefId::TypeAliasId(id) => id,
_ => unreachable!(),
+ };
+ let rhs_id = match rhs.def_id {
+ SolverDefId::TypeAliasId(id) => id,
+ _ => unreachable!(),
+ };
+ // We only compare the `associated_ty_id`s. We shouldn't have
+ // multiple bounds for an associated type in the correct Rust code,
+ // and if we do, we error out.
+ if lhs_id == rhs_id {
+ multiple_same_projection = true;
}
+ lhs_id.as_id().index().cmp(&rhs_id.as_id().index())
}
- // `WhereClause::{TypeOutlives, LifetimeOutlives}` have been filtered out
- _ => unreachable!(),
}
});
@@ -697,568 +838,195 @@
return None;
}
- lowered_bounds.first().and_then(|b| b.trait_id())?;
+ if !lowered_bounds.first().map_or(false, |b| {
+ matches!(
+ b.as_ref().skip_binder(),
+ ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_)
+ )
+ }) {
+ return None;
+ }
// As multiple occurrences of the same auto traits *are* permitted, we deduplicate the
// bounds. We shouldn't have repeated elements besides auto traits at this point.
lowered_bounds.dedup();
- Some(QuantifiedWhereClauses::from_iter(Interner, lowered_bounds))
+ Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds))
});
if let Some(bounds) = bounds {
- let bounds = crate::make_single_type_binders(bounds);
- TyKind::Dyn(DynTy {
- bounds,
- lifetime: match lifetime {
- Some(it) => match it.bound_var(Interner) {
- Some(bound_var) => bound_var
- .shifted_out_to(DebruijnIndex::new(2))
- .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
- .unwrap_or(it),
- None => it,
- },
- None => error_lifetime(),
+ let region = match lifetime {
+ Some(it) => match it.kind() {
+ rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => {
+ Region::new_bound(
+ self.interner,
+ db.shifted_out_to_binder(DebruijnIndex::from_u32(2)),
+ var,
+ )
+ }
+ _ => it,
},
- })
- .intern(Interner)
+ None => Region::new_static(self.interner),
+ };
+ Ty::new_dynamic(self.interner, bounds, region)
} else {
// FIXME: report error
// (additional non-auto traits, associated type rebound, or no resolved trait)
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.interner, ErrorGuaranteed)
}
}
- fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: Crate) -> ImplTrait {
+ fn lower_impl_trait(
+ &mut self,
+ def_id: SolverDefId,
+ bounds: &[TypeBound],
+ krate: Crate,
+ ) -> ImplTrait<'db> {
+ let interner = self.interner;
cov_mark::hit!(lower_rpit);
- let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
- let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+ let args = GenericArgs::identity_for_item(interner, def_id);
+ let self_ty = Ty::new_alias(
+ self.interner,
+ rustc_type_ir::AliasTyKind::Opaque,
+ AliasTy::new_from_args(interner, def_id, args),
+ );
+ let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
let mut predicates = Vec::new();
for b in bounds {
- predicates.extend(ctx.lower_type_bound(b, self_ty.clone(), false));
+ predicates.extend(ctx.lower_type_bound(b, self_ty, false));
}
if !ctx.unsized_types.contains(&self_ty) {
- let sized_trait =
- LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id);
+ let sized_trait = LangItem::Sized.resolve_trait(self.db, krate);
let sized_clause = sized_trait.map(|trait_id| {
- let clause = WhereClause::Implemented(TraitRef {
- trait_id,
- substitution: Substitution::from1(Interner, self_ty.clone()),
- });
- crate::wrap_empty_binders(clause)
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ trait_id.into(),
+ GenericArgs::new_from_iter(interner, [self_ty.into()]),
+ );
+ Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ))
});
predicates.extend(sized_clause);
}
predicates.shrink_to_fit();
predicates
});
- ImplTrait { bounds: crate::make_single_type_binders(predicates) }
+ ImplTrait { predicates }
}
- pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime {
+ pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
match self.resolver.resolve_lifetime(&self.store[lifetime]) {
Some(resolution) => match resolution {
- LifetimeNs::Static => static_lifetime(),
- LifetimeNs::LifetimeParam(id) => match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- let generics = self.generics();
- let idx = generics.lifetime_idx(id).unwrap();
- LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id, idx as u32))
- }
- ParamLoweringMode::Variable => {
- let idx = match self.generics().lifetime_idx(id) {
- None => return error_lifetime(),
- Some(idx) => idx,
- };
-
- LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx))
- }
+ LifetimeNs::Static => Region::new_static(self.interner),
+ LifetimeNs::LifetimeParam(id) => {
+ let idx = match self.generics().lifetime_idx(id) {
+ None => return Region::error(self.interner),
+ Some(idx) => idx,
+ };
+ self.region_param(id, idx as u32)
}
- .intern(Interner),
},
- None => error_lifetime(),
+ None => Region::error(self.interner),
}
}
}
-fn named_associated_type_shorthand_candidates<R>(
- db: &dyn HirDatabase,
- // If the type parameter is defined in an impl and we're in a method, there
- // might be additional where clauses to consider
- def: GenericDefId,
- res: TypeNs,
- assoc_name: Option<Name>,
- // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains
- // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that
- // properly (see `TyLoweringContext::select_associated_type()`).
- mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
-) -> Option<R> {
- let mut search = |t| {
- all_super_trait_refs(db, t, |t| {
- let data = t.hir_trait_id().trait_items(db);
-
- for (name, assoc_id) in &data.items {
- if let AssocItemId::TypeAliasId(alias) = assoc_id
- && let Some(result) = cb(name, &t, *alias)
- {
- return Some(result);
- }
- }
- None
- })
- };
-
- let interner = DbInterner::new_with(db, None, None);
- match res {
- TypeNs::SelfType(impl_id) => {
- let trait_ref = db.impl_trait(impl_id)?;
-
- let impl_id_as_generic_def: GenericDefId = impl_id.into();
- if impl_id_as_generic_def != def {
- let subst = TyBuilder::subst_for_def(db, impl_id, None)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
- .build();
- let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
- let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner);
- search(trait_ref)
- } else {
- search(trait_ref.skip_binder().to_chalk(interner))
- }
- }
- TypeNs::GenericParam(param_id) => {
- let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
- let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
- // FIXME: how to correctly handle higher-ranked bounds here?
- WhereClause::Implemented(tr) => search(
- tr.clone()
- .shifted_out_to(Interner, DebruijnIndex::ONE)
- .expect("FIXME unexpected higher-ranked trait bound"),
- ),
- _ => None,
- });
- if res.is_some() {
- return res;
- }
- // Handle `Self::Type` referring to own associated type in trait definitions
- if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let trait_generics = generics(db, trait_id.into());
- if trait_generics[param_id.local_id()].is_trait_self() {
- let trait_ref = TyBuilder::trait_ref(db, trait_id)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
- .build();
- return search(trait_ref);
- }
- }
- None
- }
- _ => None,
+pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
+ match m {
+ hir_def::type_ref::Mutability::Shared => Mutability::Not,
+ hir_def::type_ref::Mutability::Mut => Mutability::Mut,
}
}
+fn unknown_const(_ty: Ty<'_>) -> Const<'_> {
+ Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed))
+}
+
pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
pub(crate) fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
(!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
}
-pub(crate) fn field_types_query(
- db: &dyn HirDatabase,
- variant_id: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
- field_types_with_diagnostics_query(db, variant_id).0
-}
-
-/// Build the type of all specific fields of a struct or enum variant.
-pub(crate) fn field_types_with_diagnostics_query(
- db: &dyn HirDatabase,
- variant_id: VariantId,
-) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
- let var_data = variant_id.fields(db);
- let fields = var_data.fields();
- if fields.is_empty() {
- return (Arc::new(ArenaMap::default()), None);
- }
-
- let (resolver, def): (_, GenericDefId) = match variant_id {
- VariantId::StructId(it) => (it.resolver(db), it.into()),
- VariantId::UnionId(it) => (it.resolver(db), it.into()),
- VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
- };
- let generics = generics(db, def);
- let mut res = ArenaMap::default();
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &var_data.store,
- def,
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
- for (field_id, field_data) in fields.iter() {
- res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
- }
- (Arc::new(res), create_diagnostics(ctx.diagnostics))
-}
-
-/// This query exists only to be used when resolving short-hand associated types
-/// like `T::Item`.
-///
-/// See the analogous query in rustc and its comment:
-/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
-/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
-/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
-/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
-pub(crate) fn generic_predicates_for_param_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
- param_id: TypeOrConstParamId,
- assoc_name: Option<Name>,
-) -> GenericPredicates {
- let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return GenericPredicates(None);
- }
-
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generics.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
-
- // we have to filter out all other predicates *first*, before attempting to lower them
- let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_>| match pred {
- WherePredicate::ForLifetime { target, bound, .. }
- | WherePredicate::TypeBound { target, bound, .. } => {
- let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
- if invalid_target {
- // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
- // sized-hierarchy correctly.
- // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
- // `ctx.unsized_types`
- let lower = || -> bool {
- match bound {
- TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
- TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
- let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
- return false;
- };
- let Some(pointee_sized) =
- LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
- else {
- return false;
- };
- // Lower the path directly with `Resolver` instead of PathLoweringContext`
- // to prevent diagnostics duplications.
- ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
- |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
- )
- }
- _ => false,
- }
- }();
- if lower {
- ctx.lower_where_predicate(pred, true).for_each(drop);
- }
- return false;
- }
-
- match bound {
- &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
- // Only lower the bound if the trait could possibly define the associated
- // type we're looking for.
- let path = &ctx.store[path];
-
- let Some(assoc_name) = &assoc_name else { return true };
- let Some(TypeNs::TraitId(tr)) =
- resolver.resolve_path_in_type_ns_fully(db, path)
- else {
- return false;
- };
-
- all_super_traits(db, tr).iter().any(|tr| {
- tr.trait_items(db).items.iter().any(|(name, item)| {
- matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
- })
- })
- }
- TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
- }
- }
- WherePredicate::Lifetime { .. } => false,
- };
- let mut predicates = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- if predicate(pred, &mut ctx) {
- predicates.extend(
- ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)),
- );
- }
- }
- }
-
- let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- if !subst.is_empty(Interner) {
- let explicitly_unsized_tys = ctx.unsized_types;
- if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(
- db,
- param_id.parent,
- &explicitly_unsized_tys,
- &subst,
- &resolver,
- ) {
- predicates.extend(
- implicitly_sized_predicates
- .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
- );
- };
- }
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
-}
-
-pub(crate) fn generic_predicates_for_param_cycle_result(
- _db: &dyn HirDatabase,
- _def: GenericDefId,
- _param_id: TypeOrConstParamId,
- _assoc_name: Option<Name>,
-) -> GenericPredicates {
- GenericPredicates(None)
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
-
-impl ops::Deref for GenericPredicates {
- type Target = [Binders<crate::QuantifiedWhereClause>];
-
- fn deref(&self) -> &Self::Target {
- self.0.as_deref().unwrap_or(&[])
- }
-}
-
-/// Resolve the where clause(s) of an item with generics.
-pub(crate) fn generic_predicates_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
-) -> GenericPredicates {
- generic_predicates_filtered_by(db, def, |_, _| true).0
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// with a given filter
-fn generic_predicates_filtered_by<F>(
- db: &dyn HirDatabase,
- def: GenericDefId,
- filter: F,
-) -> (GenericPredicates, Diagnostics)
-where
- F: Fn(&WherePredicate, GenericDefId) -> bool,
-{
- let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return (GenericPredicates(None), None);
- }
-
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generics.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
-
- let mut predicates = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- if filter(pred, maybe_parent_generics.def()) {
- // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
- // If we use the parent generics
- predicates.extend(
- ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)),
- );
- }
- }
- }
-
- if !generics.is_empty() {
- let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- let explicitly_unsized_tys = ctx.unsized_types;
- if let Some(implicitly_sized_predicates) =
- implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
- {
- predicates.extend(
- implicitly_sized_predicates
- .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
- );
- };
- }
-
- (
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
- create_diagnostics(ctx.diagnostics),
- )
-}
-
-/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
-/// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
+pub(crate) fn impl_trait_query<'db>(
db: &'db dyn HirDatabase,
- def: GenericDefId,
- explicitly_unsized_tys: &'a FxHashSet<Ty>,
- substitution: &'subst Substitution,
- resolver: &Resolver<'db>,
-) -> Option<impl Iterator<Item = WhereClause>> {
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
-
- let trait_self_idx = trait_self_param_idx(db, def);
-
- Some(
- substitution
- .iter(Interner)
- .enumerate()
- .filter_map(
- move |(idx, generic_arg)| {
- if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
- },
- )
- .filter_map(|generic_arg| generic_arg.ty(Interner))
- .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty))
- .map(move |self_ty| {
- WhereClause::Implemented(TraitRef {
- trait_id: sized_trait,
- substitution: Substitution::from1(Interner, self_ty.clone()),
- })
- }),
- )
+ impl_id: ImplId,
+) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
+ db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericDefaults(Option<Arc<[Binders<crate::GenericArg>]>>);
-
-impl ops::Deref for GenericDefaults {
- type Target = [Binders<crate::GenericArg>];
-
- fn deref(&self) -> &Self::Target {
- self.0.as_deref().unwrap_or(&[])
- }
-}
-
-pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
- db.generic_defaults_with_diagnostics(def).0
-}
-
-/// Resolve the default type params from generics.
-///
-/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
-pub(crate) fn generic_defaults_with_diagnostics_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
- let generic_params = generics(db, def);
- if generic_params.is_empty() {
- return (GenericDefaults(None), None);
- }
- let resolver = def.resolver(db);
-
+pub(crate) fn impl_trait_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> {
+ let impl_data = db.impl_signature(impl_id);
+ let resolver = impl_id.resolver(db);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
- generic_params.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
- .with_type_param_mode(ParamLoweringMode::Variable);
- let mut idx = 0;
- let mut has_any_default = false;
- let mut defaults = generic_params
- .iter_parents_with_store()
- .map(|((id, p), store)| {
- ctx.store = store;
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
- has_any_default |= has_default;
- idx += 1;
- result
- })
- .collect::<Vec<_>>();
- ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
- defaults.extend(generic_params.iter_self().map(|(id, p)| {
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
- has_any_default |= has_default;
- idx += 1;
- result
- }));
- let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
- let defaults = if has_any_default {
- GenericDefaults(Some(Arc::from_iter(defaults)))
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ );
+ let self_ty = db.impl_self_ty(impl_id).skip_binder();
+ let target_trait = impl_data.target_trait.as_ref()?;
+ let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
+ Some((trait_ref, create_diagnostics(ctx.diagnostics)))
+}
+
+pub(crate) fn return_type_impl_traits<'db>(
+ db: &'db dyn HirDatabase,
+ def: hir_def::FunctionId,
+) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
+ // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
+ let data = db.function_signature(def);
+ let resolver = def.resolver(db);
+ let mut ctx_ret =
+ TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ if let Some(ret_type) = data.ret_type {
+ let _ret = ctx_ret.lower_ty(ret_type);
+ }
+ let return_type_impl_traits =
+ ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
+ if return_type_impl_traits.impl_traits.is_empty() {
+ None
} else {
- GenericDefaults(None)
- };
- return (defaults, diagnostics);
-
- fn handle_generic_param(
- ctx: &mut TyLoweringContext<'_>,
- idx: usize,
- id: GenericParamId,
- p: GenericParamDataRef<'_>,
- generic_params: &Generics,
- ) -> (Binders<crate::GenericArg>, bool) {
- let binders = variable_kinds_from_iter(ctx.db, generic_params.iter_id().take(idx));
- match p {
- GenericParamDataRef::TypeParamData(p) => {
- let ty = p.default.as_ref().map_or_else(
- || TyKind::Error.intern(Interner),
- |ty| {
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden (FIXME: report diagnostic)
- fallback_bound_vars(ctx.lower_ty(*ty), idx)
- },
- );
- (Binders::new(binders, ty.cast(Interner)), p.default.is_some())
- }
- GenericParamDataRef::ConstParamData(p) => {
- let GenericParamId::ConstParamId(id) = id else {
- unreachable!("Unexpected lifetime or type argument")
- };
-
- let mut val = p.default.as_ref().map_or_else(
- || unknown_const_as_generic(ctx.db.const_param_ty(id)),
- |c| {
- let param_ty = ctx.lower_ty(p.ty);
- let c = ctx.lower_const(c, param_ty);
- c.cast(Interner)
- },
- );
- // Each default can only refer to previous parameters, see above.
- val = fallback_bound_vars(val, idx);
- (Binders::new(binders, val), p.default.is_some())
- }
- GenericParamDataRef::LifetimeParamData(_) => {
- (Binders::new(binders, error_lifetime().cast(Interner)), false)
- }
- }
+ Some(Arc::new(EarlyBinder::bind(return_type_impl_traits)))
}
}
-pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
- _db: &dyn HirDatabase,
- _def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
- (GenericDefaults(None), None)
+pub(crate) fn type_alias_impl_traits<'db>(
+ db: &'db dyn HirDatabase,
+ def: hir_def::TypeAliasId,
+) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
+ let data = db.type_alias_signature(def);
+ let resolver = def.resolver(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ if let Some(type_ref) = data.ty {
+ let _ty = ctx.lower_ty(type_ref);
+ }
+ let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
+ if type_alias_impl_traits.impl_traits.is_empty() {
+ None
+ } else {
+ Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits)))
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1293,18 +1061,203 @@
}
}
-pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
- const_param_ty_with_diagnostics_query(db, def).0
+/// Build the declared type of an item. This depends on the namespace; e.g. for
+/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
+/// the constructor function `(usize) -> Foo` which lives in the values
+/// namespace.
+pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_with(db, None, None);
+ match def {
+ TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)),
+ TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt(
+ interner,
+ it,
+ GenericArgs::identity_for_item(interner, it.into()),
+ )),
+ TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
+ }
+}
+
+/// Build the declared type of a function. This should not need to look at the
+/// function body.
+fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_with(db, None, None);
+ EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::FunctionId(def).into(),
+ GenericArgs::identity_for_item(interner, def.into()),
+ ))
+}
+
+/// Build the declared type of a const.
+fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
+ let resolver = def.resolver(db);
+ let data = db.const_signature(def);
+ let parent = def.loc(db).container;
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent));
+ EarlyBinder::bind(ctx.lower_ty(data.type_ref))
+}
+
+/// Build the declared type of a static.
+fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
+ let resolver = def.resolver(db);
+ let data = db.static_signature(def);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner)));
+ EarlyBinder::bind(ctx.lower_ty(data.type_ref))
+}
+
+/// Build the type of a tuple struct constructor.
+fn type_for_struct_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: StructId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ let struct_data = def.fields(db);
+ match struct_data.shape {
+ FieldsShape::Record => None,
+ FieldsShape::Unit => Some(type_for_adt(db, def.into())),
+ FieldsShape::Tuple => {
+ let interner = DbInterner::new_with(db, None, None);
+ Some(EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::StructId(def).into(),
+ GenericArgs::identity_for_item(interner, def.into()),
+ )))
+ }
+ }
+}
+
+/// Build the type of a tuple enum variant constructor.
+fn type_for_enum_variant_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: EnumVariantId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ let struct_data = def.fields(db);
+ match struct_data.shape {
+ FieldsShape::Record => None,
+ FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())),
+ FieldsShape::Tuple => {
+ let interner = DbInterner::new_with(db, None, None);
+ Some(EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::EnumVariantId(def).into(),
+ GenericArgs::identity_for_item(interner, def.loc(db).parent.into()),
+ )))
+ }
+ }
+}
+
+pub(crate) fn value_ty_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: ValueTyDefId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ match def {
+ ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
+ ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
+ ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
+ ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
+ ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
+ ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
+ }
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ t: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ let type_alias_data = db.type_alias_signature(t);
+ let mut diags = None;
+ let resolver = t.resolver(db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
+ EarlyBinder::bind(Ty::new_foreign(interner, t.into()))
+ } else {
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ t.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ let res = EarlyBinder::bind(
+ type_alias_data
+ .ty
+ .map(|type_ref| ctx.lower_ty(type_ref))
+ .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)),
+ );
+ diags = create_diagnostics(ctx.diagnostics);
+ res
+ };
+ (inner, diags)
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>(
+ db: &'db dyn HirDatabase,
+ _adt: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn impl_self_ty_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> EarlyBinder<'db, Ty<'db>> {
+ db.impl_self_ty_with_diagnostics(impl_id).0
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ let resolver = impl_id.resolver(db);
+
+ let impl_data = db.impl_signature(impl_id);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ );
+ let ty = ctx.lower_ty(impl_data.self_ty);
+ assert!(!ty.has_escaping_bound_vars());
+ (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics))
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
+ db: &dyn HirDatabase,
+ _impl_id: ImplId,
+) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) {
+ (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
+ db.const_param_ty_with_diagnostics(def).0
}
// returns None if def is a type arg
-pub(crate) fn const_param_ty_with_diagnostics_query(
- db: &dyn HirDatabase,
+pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
def: ConstParamId,
-) -> (Ty, Diagnostics) {
+) -> (Ty<'db>, Diagnostics) {
let (parent_data, store) = db.generic_params_and_store(def.parent());
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
@@ -1315,103 +1268,912 @@
let ty = match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
- Ty::new(Interner, TyKind::Error)
+ Ty::new_error(interner, ErrorGuaranteed)
}
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
};
(ty, create_diagnostics(ctx.diagnostics))
}
-pub(crate) fn const_param_ty_cycle_result(
- _: &dyn HirDatabase,
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
+ db: &'db dyn HirDatabase,
_: crate::db::HirDatabaseData,
- _: ConstParamId,
-) -> Ty {
- TyKind::Error.intern(Interner)
+ def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+ let resolver = def.parent().resolver(db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ (Ty::new_error(interner, ErrorGuaranteed), None)
}
-pub(crate) fn return_type_impl_traits(
- db: &dyn HirDatabase,
- def: hir_def::FunctionId,
-) -> Option<Arc<Binders<ImplTraits>>> {
- // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
- let data = db.function_signature(def);
- let resolver = def.resolver(db);
- let mut ctx_ret =
- TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- if let Some(ret_type) = data.ret_type {
- let _ret = ctx_ret.lower_ty(ret_type);
- }
- let generics = generics(db, def.into());
- let return_type_impl_traits =
- ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
- if return_type_impl_traits.impl_traits.is_empty() {
- None
- } else {
- Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
- }
+pub(crate) fn field_types_query<'db>(
+ db: &'db dyn HirDatabase,
+ variant_id: VariantId,
+) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
+ db.field_types_with_diagnostics(variant_id).0
}
-pub(crate) fn type_alias_impl_traits(
- db: &dyn HirDatabase,
- def: hir_def::TypeAliasId,
-) -> Option<Arc<Binders<ImplTraits>>> {
- let data = db.type_alias_signature(def);
+/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) fn field_types_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ variant_id: VariantId,
+) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) {
+ let var_data = variant_id.fields(db);
+ let fields = var_data.fields();
+ if fields.is_empty() {
+ return (Arc::new(ArenaMap::default()), None);
+ }
+
+ let (resolver, def): (_, GenericDefId) = match variant_id {
+ VariantId::StructId(it) => (it.resolver(db), it.into()),
+ VariantId::UnionId(it) => (it.resolver(db), it.into()),
+ VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
+ };
+ let mut res = ArenaMap::default();
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &var_data.store,
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ for (field_id, field_data) in var_data.fields().iter() {
+ res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref)));
+ }
+ (Arc::new(res), create_diagnostics(ctx.diagnostics))
+}
+
+/// This query exists only to be used when resolving short-hand associated types
+/// like `T::Item`.
+///
+/// See the analogous query in rustc and its comment:
+/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
+/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
+/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
+/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
+#[tracing::instrument(skip(db), ret)]
+pub(crate) fn generic_predicates_for_param_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ param_id: TypeOrConstParamId,
+ assoc_name: Option<Name>,
+) -> GenericPredicates<'db> {
+ let generics = generics(db, def);
+ let interner = DbInterner::new_with(db, None, None);
let resolver = def.resolver(db);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
- &data.store,
- def.into(),
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ );
+
+ // we have to filter out all other predicates *first*, before attempting to lower them
+ let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
+ WherePredicate::ForLifetime { target, bound, .. }
+ | WherePredicate::TypeBound { target, bound, .. } => {
+ let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
+ if invalid_target {
+ // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
+ // sized-hierarchy correctly.
+ // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
+ // `ctx.unsized_types`
+ let lower = || -> bool {
+ match bound {
+ TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
+ TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
+ let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
+ return false;
+ };
+ let Some(pointee_sized) =
+ LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
+ else {
+ return false;
+ };
+ // Lower the path directly with `Resolver` instead of PathLoweringContext`
+ // to prevent diagnostics duplications.
+ ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
+ |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
+ )
+ }
+ _ => false,
+ }
+ }();
+ if lower {
+ ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
+ .for_each(drop);
+ }
+ return false;
+ }
+
+ match bound {
+ &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
+ // Only lower the bound if the trait could possibly define the associated
+ // type we're looking for.
+ let path = &ctx.store[path];
+
+ let Some(assoc_name) = &assoc_name else { return true };
+ let Some(TypeNs::TraitId(tr)) =
+ resolver.resolve_path_in_type_ns_fully(db, path)
+ else {
+ return false;
+ };
+
+ rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
+ tr.0.trait_items(db).items.iter().any(|(name, item)| {
+ matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
+ })
+ })
+ }
+ TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
+ }
+ }
+ WherePredicate::Lifetime { .. } => false,
+ };
+ let mut predicates = Vec::new();
+ for maybe_parent_generics in
+ std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+ {
+ ctx.store = maybe_parent_generics.store();
+ for pred in maybe_parent_generics.where_predicates() {
+ if predicate(pred, &mut ctx) {
+ predicates.extend(ctx.lower_where_predicate(
+ pred,
+ true,
+ maybe_parent_generics,
+ PredicateFilter::All,
+ ));
+ }
+ }
+ }
+
+ let args = GenericArgs::identity_for_item(interner, def.into());
+ if !args.is_empty() {
+ let explicitly_unsized_tys = ctx.unsized_types;
+ if let Some(implicitly_sized_predicates) =
+ implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver)
+ {
+ predicates.extend(implicitly_sized_predicates);
+ };
+ }
+ GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+}
+
+pub(crate) fn generic_predicates_for_param_cycle_result(
+ _db: &dyn HirDatabase,
+ _def: GenericDefId,
+ _param_id: TypeOrConstParamId,
+ _assoc_name: Option<Name>,
+) -> GenericPredicates<'_> {
+ GenericPredicates(None)
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
+
+impl<'db> GenericPredicates<'db> {
+ #[inline]
+ pub fn instantiate(
+ &self,
+ interner: DbInterner<'db>,
+ args: GenericArgs<'db>,
+ ) -> Option<impl Iterator<Item = Clause<'db>>> {
+ self.0
+ .as_ref()
+ .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
+ }
+
+ #[inline]
+ pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> {
+ self.0.as_ref().map(|it| it.iter().copied())
+ }
+}
+
+impl<'db> ops::Deref for GenericPredicates<'db> {
+ type Target = [Clause<'db>];
+
+ fn deref(&self) -> &Self::Target {
+ self.0.as_deref().unwrap_or(&[])
+ }
+}
+
+pub(crate) fn trait_environment_for_body_query(
+ db: &dyn HirDatabase,
+ def: DefWithBodyId,
+) -> Arc<TraitEnvironment<'_>> {
+ let Some(def) = def.as_generic_def_id(db) else {
+ let krate = def.module(db).krate();
+ return TraitEnvironment::empty(krate);
+ };
+ db.trait_environment(def)
+}
+
+pub(crate) fn trait_environment_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+) -> Arc<TraitEnvironment<'db>> {
+ let generics = generics(db, def);
+ if generics.has_no_predicates() && generics.is_empty() {
+ return TraitEnvironment::empty(def.krate(db));
+ }
+
+ let resolver = def.resolver(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ let mut traits_in_scope = Vec::new();
+ let mut clauses = Vec::new();
+ for maybe_parent_generics in
+ std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+ {
+ ctx.store = maybe_parent_generics.store();
+ for pred in maybe_parent_generics.where_predicates() {
+ for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
+ if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
+ traits_in_scope.push((tr.self_ty(), tr.def_id().0));
+ }
+ clauses.push(pred);
+ }
+ }
+ }
+
+ if let Some(trait_id) = def.assoc_trait_container(db) {
+ // add `Self: Trait<T1, T2, ...>` to the environment in trait
+ // function default implementations (and speculative code
+ // inside consts or type aliases)
+ cov_mark::hit!(trait_self_implements_self);
+ let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
+ let clause = Clause(Predicate::new(
+ ctx.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
+ TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
+ ))),
+ ));
+ clauses.push(clause);
+ }
+
+ let explicitly_unsized_tys = ctx.unsized_types;
+
+ let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+ if let Some(sized_trait) = sized_trait {
+ let (mut generics, mut def_id) =
+ (crate::next_solver::generics::generics(db, def.into()), def);
+ loop {
+ let self_idx = trait_self_param_idx(db, def_id);
+ for (idx, p) in generics.own_params.iter().enumerate() {
+ if let Some(self_idx) = self_idx
+ && p.index() as usize == self_idx
+ {
+ continue;
+ }
+ let GenericParamId::TypeParamId(param_id) = p.id else {
+ continue;
+ };
+ let idx = idx as u32 + generics.parent_count as u32;
+ let param_ty = Ty::new_param(ctx.interner, param_id, idx);
+ if explicitly_unsized_tys.contains(¶m_ty) {
+ continue;
+ }
+ let trait_ref = TraitRef::new_from_args(
+ ctx.interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
+ );
+ let clause = Clause(Predicate::new(
+ ctx.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ));
+ clauses.push(clause);
+ }
+
+ if let Some(g) = generics.parent {
+ generics = crate::next_solver::generics::generics(db, g.into());
+ def_id = g;
+ } else {
+ break;
+ }
+ }
+ }
+
+ let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
+ let clauses = Clauses::new_from_iter(ctx.interner, clauses);
+ let env = ParamEnv { clauses };
+
+ TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
+}
+
+#[derive(Copy, Clone, Debug)]
+pub(crate) enum PredicateFilter {
+ SelfTrait,
+ All,
+}
+
+/// Resolve the where clause(s) of an item with generics.
+#[tracing::instrument(skip(db))]
+pub(crate) fn generic_predicates_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+) -> GenericPredicates<'db> {
+ generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0
+}
+
+pub(crate) fn generic_predicates_without_parent_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+) -> GenericPredicates<'db> {
+ generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// except the ones inherited from the parent
+pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+) -> (GenericPredicates<'db>, Diagnostics) {
+ generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def)
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// with a given filter
+#[tracing::instrument(skip(db, filter), ret)]
+pub(crate) fn generic_predicates_filtered_by<'db, F>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ predicate_filter: PredicateFilter,
+ filter: F,
+) -> (GenericPredicates<'db>, Diagnostics)
+where
+ F: Fn(GenericDefId) -> bool,
+{
+ let generics = generics(db, def);
+ let resolver = def.resolver(db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ );
+
+ let mut predicates = Vec::new();
+ for maybe_parent_generics in
+ std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+ {
+ ctx.store = maybe_parent_generics.store();
+ for pred in maybe_parent_generics.where_predicates() {
+ tracing::debug!(?pred);
+ if filter(maybe_parent_generics.def()) {
+ predicates.extend(ctx.lower_where_predicate(
+ pred,
+ false,
+ maybe_parent_generics,
+ predicate_filter,
+ ));
+ }
+ }
+ }
+
+ let explicitly_unsized_tys = ctx.unsized_types;
+
+ let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+ if let Some(sized_trait) = sized_trait {
+ let mut add_sized_clause = |param_idx, param_id, param_data| {
+ let (
+ GenericParamId::TypeParamId(param_id),
+ GenericParamDataRef::TypeParamData(param_data),
+ ) = (param_id, param_data)
+ else {
+ return;
+ };
+
+ if param_data.provenance == TypeParamProvenance::TraitSelf {
+ return;
+ }
+
+ let param_ty = Ty::new_param(interner, param_id, param_idx);
+ if explicitly_unsized_tys.contains(¶m_ty) {
+ return;
+ }
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(interner, [param_ty.into()]),
+ );
+ let clause = Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ));
+ predicates.push(clause);
+ };
+ if generics.parent_generics().is_some_and(|parent| filter(parent.def())) {
+ generics.iter_parent().enumerate().for_each(|(param_idx, (param_id, param_data))| {
+ add_sized_clause(param_idx as u32, param_id, param_data);
+ });
+ }
+ if filter(def) {
+ let parent_params_len = generics.len_parent();
+ generics.iter_self().enumerate().for_each(|(param_idx, (param_id, param_data))| {
+ add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data);
+ });
+ }
+ }
+
+ // FIXME: rustc gathers more predicates by recursing through resulting trait predicates.
+ // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715
+
+ (
+ GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
+ create_diagnostics(ctx.diagnostics),
+ )
+}
+
+/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
+/// Exception is Self of a trait def.
+fn implicitly_sized_clauses<'a, 'subst, 'db>(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
+ args: &'subst GenericArgs<'db>,
+ resolver: &Resolver<'db>,
+) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?;
+
+ let trait_self_idx = trait_self_param_idx(db, def);
+
+ Some(
+ args.iter()
+ .enumerate()
+ .filter_map(
+ move |(idx, generic_arg)| {
+ if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
+ },
+ )
+ .filter_map(|generic_arg| generic_arg.as_type())
+ .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
+ .map(move |self_ty| {
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(interner, [self_ty.into()]),
+ );
+ Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ))
+ }),
+ )
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericDefaults<'db>(Option<Arc<[Option<EarlyBinder<'db, GenericArg<'db>>>]>>);
+
+impl<'db> GenericDefaults<'db> {
+ #[inline]
+ pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> {
+ self.0.as_ref()?[idx]
+ }
+}
+
+pub(crate) fn generic_defaults_query(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+) -> GenericDefaults<'_> {
+ db.generic_defaults_with_diagnostics(def).0
+}
+
+/// Resolve the default type params from generics.
+///
+/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
+pub(crate) fn generic_defaults_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+) -> (GenericDefaults<'_>, Diagnostics) {
+ let generic_params = generics(db, def);
+ if generic_params.is_empty() {
+ return (GenericDefaults(None), None);
+ }
+ let resolver = def.resolver(db);
+
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generic_params.store(),
+ def,
LifetimeElisionKind::AnonymousReportError,
)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- if let Some(type_ref) = data.ty {
- let _ty = ctx.lower_ty(type_ref);
- }
- let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
- if type_alias_impl_traits.impl_traits.is_empty() {
- None
+ .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed);
+ let mut idx = 0;
+ let mut has_any_default = false;
+ let mut defaults = generic_params
+ .iter_parents_with_store()
+ .map(|((_id, p), store)| {
+ ctx.store = store;
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
+ has_any_default |= has_default;
+ idx += 1;
+ result
+ })
+ .collect::<Vec<_>>();
+ ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
+ defaults.extend(generic_params.iter_self().map(|(_id, p)| {
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
+ has_any_default |= has_default;
+ idx += 1;
+ result
+ }));
+ let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
+ let defaults = if has_any_default {
+ GenericDefaults(Some(Arc::from_iter(defaults)))
} else {
- let generics = generics(db, def.into());
- Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
+ GenericDefaults(None)
+ };
+ return (defaults, diagnostics);
+
+ fn handle_generic_param<'db>(
+ ctx: &mut TyLoweringContext<'db, '_>,
+ idx: usize,
+ p: GenericParamDataRef<'_>,
+ ) -> (Option<EarlyBinder<'db, GenericArg<'db>>>, bool) {
+ ctx.lowering_param_default(idx as u32);
+ match p {
+ GenericParamDataRef::TypeParamData(p) => {
+ let ty = p.default.map(|ty| ctx.lower_ty(ty));
+ (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some())
+ }
+ GenericParamDataRef::ConstParamData(p) => {
+ let val = p.default.map(|c| {
+ let param_ty = ctx.lower_ty(p.ty);
+ let c = ctx.lower_const(c, param_ty);
+ c.into()
+ });
+ (val.map(EarlyBinder::bind), p.default.is_some())
+ }
+ GenericParamDataRef::LifetimeParamData(_) => (None, false),
+ }
}
}
-pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
- match m {
- hir_def::type_ref::Mutability::Shared => Mutability::Not,
- hir_def::type_ref::Mutability::Mut => Mutability::Mut,
+pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
+ _db: &dyn HirDatabase,
+ _def: GenericDefId,
+) -> (GenericDefaults<'_>, Diagnostics) {
+ (GenericDefaults(None), None)
+}
+
+/// Build the signature of a callable item (function, struct or enum variant).
+pub(crate) fn callable_item_signature_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: CallableDefId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+ match def {
+ CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
+ CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
+ CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
}
}
-/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
-/// parameter whose index is `param_index`. A `BoundVar` is free when it appears after the
-/// generic parameter of `param_index`.
-fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
- s: T,
- param_index: usize,
-) -> T {
- let is_allowed = |index| (0..param_index).contains(&index);
+fn fn_sig_for_fn<'db>(
+ db: &'db dyn HirDatabase,
+ def: FunctionId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+ let data = db.function_signature(def);
+ let resolver = def.resolver(db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let mut ctx_params = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::for_fn_params(&data),
+ );
+ let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
- crate::fold_free_vars(
- s,
- |bound, binders| {
- if bound.index_if_innermost().is_none_or(is_allowed) {
- bound.shifted_in_from(binders).to_ty(Interner)
- } else {
- TyKind::Error.intern(Interner)
+ let ret = match data.ret_type {
+ Some(ret_type) => {
+ let mut ctx_ret = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::for_fn_ret(interner),
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ ctx_ret.lower_ty(ret_type)
+ }
+ None => Ty::new_tup(interner, &[]),
+ };
+
+ let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret)));
+ // If/when we track late bound vars, we need to switch this to not be `dummy`
+ EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig {
+ abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+ c_variadic: data.is_varargs(),
+ safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+ inputs_and_output,
+ }))
+}
+
+fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_with(db, None, None);
+ let args = GenericArgs::identity_for_item(interner, adt.into());
+ let ty = Ty::new_adt(interner, adt, args);
+ EarlyBinder::bind(ty)
+}
+
+fn fn_sig_for_struct_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: StructId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+ let field_tys = db.field_types(def.into());
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
+ let ret = type_for_adt(db, def.into()).skip_binder();
+
+ let inputs_and_output =
+ Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
+ EarlyBinder::bind(Binder::dummy(FnSig {
+ abi: FnAbi::RustCall,
+ c_variadic: false,
+ safety: Safety::Safe,
+ inputs_and_output,
+ }))
+}
+
+fn fn_sig_for_enum_variant_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: EnumVariantId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+ let field_tys = db.field_types(def.into());
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
+ let parent = def.lookup(db).parent;
+ let ret = type_for_adt(db, parent.into()).skip_binder();
+
+ let inputs_and_output =
+ Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
+ EarlyBinder::bind(Binder::dummy(FnSig {
+ abi: FnAbi::RustCall,
+ c_variadic: false,
+ safety: Safety::Safe,
+ inputs_and_output,
+ }))
+}
+
+// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way
+pub(crate) fn associated_ty_item_bounds<'db>(
+ db: &'db dyn HirDatabase,
+ type_alias: TypeAliasId,
+) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
+ let type_alias_data = db.type_alias_signature(type_alias);
+ let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ type_alias.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ // FIXME: we should never create non-existential predicates in the first place
+ // For now, use an error type so we don't run into dummy binder issues
+ let self_ty = Ty::new_error(interner, ErrorGuaranteed);
+
+ let mut bounds = Vec::new();
+ for bound in &type_alias_data.bounds {
+ ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
+ if let Some(bound) = pred
+ .kind()
+ .map_bound(|c| match c {
+ rustc_type_ir::ClauseKind::Trait(t) => {
+ let id = t.def_id();
+ let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+ if is_auto {
+ Some(ExistentialPredicate::AutoTrait(t.def_id()))
+ } else {
+ Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
+ interner,
+ t.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ t.trait_ref.args.iter().skip(1),
+ ),
+ )))
+ }
+ }
+ rustc_type_ir::ClauseKind::Projection(p) => Some(
+ ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
+ interner,
+ p.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ p.projection_term.args.iter().skip(1),
+ ),
+ p.term,
+ )),
+ ),
+ rustc_type_ir::ClauseKind::TypeOutlives(_) => None,
+ rustc_type_ir::ClauseKind::RegionOutlives(_)
+ | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+ | rustc_type_ir::ClauseKind::WellFormed(_)
+ | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+ | rustc_type_ir::ClauseKind::HostEffect(_)
+ | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+ })
+ .transpose()
+ {
+ bounds.push(bound);
}
- },
- |ty, bound, binders| {
- if bound.index_if_innermost().is_none_or(is_allowed) {
- bound.shifted_in_from(binders).to_const(Interner, ty)
- } else {
- unknown_const(ty)
+ });
+ }
+
+ if !ctx.unsized_types.contains(&self_ty)
+ && let Some(sized_trait) = LangItem::Sized.resolve_trait(db, resolver.krate())
+ {
+ let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
+ interner,
+ sized_trait.into(),
+ [] as [GenericArg<'_>; 0],
+ )));
+ bounds.push(sized_clause);
+ }
+
+ EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
+}
+
+pub(crate) fn associated_type_by_name_including_super_traits<'db>(
+ db: &'db dyn HirDatabase,
+ trait_ref: TraitRef<'db>,
+ name: &Name,
+) -> Option<(TraitRef<'db>, TypeAliasId)> {
+ let interner = DbInterner::new_with(db, None, None);
+ rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
+ let trait_id = t.as_ref().skip_binder().def_id.0;
+ let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
+ Some((t.skip_binder(), assoc_type))
+ })
+}
+
+pub fn associated_type_shorthand_candidates(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+ res: TypeNs,
+ mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
+) -> Option<TypeAliasId> {
+ let interner = DbInterner::new_with(db, None, None);
+ named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
+ cb(name, id).then_some(id)
+ })
+}
+
+#[tracing::instrument(skip(interner, check_alias))]
+fn named_associated_type_shorthand_candidates<'db, R>(
+ interner: DbInterner<'db>,
+ // If the type parameter is defined in an impl and we're in a method, there
+ // might be additional where clauses to consider
+ def: GenericDefId,
+ res: TypeNs,
+ assoc_name: Option<Name>,
+ mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+ let db = interner.db;
+ let mut search = |t: TraitRef<'db>| -> Option<R> {
+ let mut checked_traits = FxHashSet::default();
+ let mut check_trait = |trait_ref: TraitRef<'db>| {
+ let trait_id = trait_ref.def_id.0;
+ let name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_id, ?name);
+ if !checked_traits.insert(trait_id) {
+ return None;
}
- },
- )
+ let data = trait_id.trait_items(db);
+
+ tracing::debug!(?data.items);
+ for (name, assoc_id) in &data.items {
+ if let &AssocItemId::TypeAliasId(alias) = assoc_id
+ && let Some(ty) = check_alias(name, trait_ref, alias)
+ {
+ return Some(ty);
+ }
+ }
+ None
+ };
+ let mut stack: SmallVec<[_; 4]> = smallvec![t];
+ while let Some(trait_ref) = stack.pop() {
+ if let Some(alias) = check_trait(trait_ref) {
+ return Some(alias);
+ }
+ for pred in generic_predicates_filtered_by(
+ db,
+ GenericDefId::TraitId(trait_ref.def_id.0),
+ PredicateFilter::SelfTrait,
+ // We are likely in the midst of lowering generic predicates of `def`.
+ // So, if we allow `pred == def` we might fall into an infinite recursion.
+ // Actually, we have already checked for the case `pred == def` above as we started
+ // with a stack including `trait_id`
+ |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
+ )
+ .0
+ .deref()
+ {
+ tracing::debug!(?pred);
+ let sup_trait_ref = match pred.kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
+ _ => continue,
+ };
+ let sup_trait_ref =
+ EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
+ stack.push(sup_trait_ref);
+ }
+ tracing::debug!(?stack);
+ }
+
+ None
+ };
+
+ match res {
+ TypeNs::SelfType(impl_id) => {
+ let trait_ref = db.impl_trait(impl_id)?;
+
+ // FIXME(next-solver): same method in `lower` checks for impl or not
+ // Is that needed here?
+
+ // we're _in_ the impl -- the binders get added back later. Correct,
+ // but it would be nice to make this more explicit
+ search(trait_ref.skip_binder())
+ }
+ TypeNs::GenericParam(param_id) => {
+ // Handle `Self::Type` referring to own associated type in trait definitions
+ // This *must* be done first to avoid cycles with
+ // `generic_predicates_for_param`, but not sure that it's sufficient,
+ if let GenericDefId::TraitId(trait_id) = param_id.parent() {
+ let trait_name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_name);
+ let trait_generics = generics(db, trait_id.into());
+ tracing::debug!(?trait_generics);
+ if trait_generics[param_id.local_id()].is_trait_self() {
+ let args = GenericArgs::identity_for_item(interner, trait_id.into());
+ let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
+ tracing::debug!(?args, ?trait_ref);
+ return search(trait_ref);
+ }
+ }
+
+ let predicates =
+ db.generic_predicates_for_param(def, param_id.into(), assoc_name.clone());
+ predicates
+ .iter()
+ .find_map(|pred| match (*pred).kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
+ _ => None,
+ })
+ .and_then(|trait_predicate| {
+ let trait_ref = trait_predicate.trait_ref;
+ assert!(
+ !trait_ref.has_escaping_bound_vars(),
+ "FIXME unexpected higher-ranked trait bound"
+ );
+ search(trait_ref)
+ })
+ }
+ _ => None,
+ }
}
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 09a256a..9ba0da6 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -1,42 +1,52 @@
//! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
-use chalk_ir::{BoundVar, cast::Cast, fold::Shift};
use either::Either;
use hir_def::{
- GenericDefId, GenericParamId, TraitId,
+ GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
expr_store::{
- ExpressionStore,
- path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
+ ExpressionStore, HygieneId,
+ path::{
+ GenericArg as HirGenericArg, GenericArgs as HirGenericArgs, GenericArgsParentheses,
+ Path, PathSegment, PathSegments,
+ },
},
hir::generics::{
GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
},
- resolver::TypeNs,
+ resolver::{ResolveValueResult, TypeNs, ValueNs},
signatures::TraitFlags,
type_ref::{TypeRef, TypeRefId},
};
+use hir_expand::name::Name;
+use rustc_type_ir::{
+ AliasTerm, AliasTy, AliasTyKind,
+ inherent::{GenericArgs as _, Region as _, SliceLike, Ty as _},
+};
use smallvec::SmallVec;
use stdx::never;
use crate::{
- AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, IncorrectGenericsLenKind,
- Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy,
- QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, WhereClause,
- consteval_chalk::{unknown_const, unknown_const_as_generic},
+ GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
+ PathLoweringDiagnostic, TyDefId, ValueTyDefId,
+ consteval::{unknown_const, unknown_const_as_generic},
db::HirDatabase,
- error_lifetime,
generics::{Generics, generics},
- lower::{LifetimeElisionKind, TyLoweringContext, named_associated_type_shorthand_candidates},
- next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, NextSolverToChalk},
+ lower::{
+ LifetimeElisionKind, PathDiagnosticCallbackData, named_associated_type_shorthand_candidates,
},
- to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
- utils::associated_type_by_name_including_super_traits,
+ next_solver::{
+ Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
+ ProjectionPredicate, Region, TraitRef, Ty,
+ },
+};
+
+use super::{
+ ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
+ const_param_ty_query, ty_query,
};
type CallbackData<'a, 'db> = Either<
- super::PathDiagnosticCallbackData,
+ PathDiagnosticCallbackData,
crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>,
>;
@@ -45,12 +55,12 @@
pub(crate) struct PathDiagnosticCallback<'a, 'db> {
pub(crate) data: CallbackData<'a, 'db>,
pub(crate) callback:
- fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic),
+ fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
}
-pub(crate) struct PathLoweringContext<'a, 'b> {
- ctx: &'a mut TyLoweringContext<'b>,
- on_diagnostic: PathDiagnosticCallback<'a, 'b>,
+pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
+ ctx: &'a mut TyLoweringContext<'db, 'b>,
+ on_diagnostic: PathDiagnosticCallback<'a, 'db>,
path: &'a Path,
segments: PathSegments<'a>,
current_segment_idx: usize,
@@ -58,11 +68,11 @@
current_or_prev_segment: PathSegment<'a>,
}
-impl<'a, 'b> PathLoweringContext<'a, 'b> {
+impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
#[inline]
pub(crate) fn new(
- ctx: &'a mut TyLoweringContext<'b>,
- on_diagnostic: PathDiagnosticCallback<'a, 'b>,
+ ctx: &'a mut TyLoweringContext<'db, 'b>,
+ on_diagnostic: PathDiagnosticCallback<'a, 'db>,
path: &'a Path,
) -> Self {
let segments = path.segments();
@@ -84,7 +94,7 @@
}
#[inline]
- pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'b> {
+ pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> {
self.ctx
}
@@ -110,10 +120,24 @@
}
#[inline]
+ pub(crate) fn ignore_last_segment(&mut self) {
+ self.segments = self.segments.strip_last();
+ }
+
+ #[inline]
+ pub(crate) fn set_current_segment(&mut self, segment: usize) {
+ self.current_segment_idx = segment;
+ self.current_or_prev_segment = self
+ .segments
+ .get(segment)
+ .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
+ }
+
+ #[inline]
fn with_lifetime_elision<T>(
&mut self,
- lifetime_elision: LifetimeElisionKind,
- f: impl FnOnce(&mut PathLoweringContext<'_, '_>) -> T,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
) -> T {
let old_lifetime_elision =
std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
@@ -124,12 +148,13 @@
pub(crate) fn lower_ty_relative_path(
&mut self,
- ty: Ty,
+ ty: Ty<'db>,
// We need the original resolution to lower `Self::AssocTy` correctly
res: Option<TypeNs>,
infer_args: bool,
- ) -> (Ty, Option<TypeNs>) {
- match self.segments.len() - self.current_segment_idx {
+ ) -> (Ty<'db>, Option<TypeNs>) {
+ let remaining_segments = self.segments.len() - self.current_segment_idx;
+ match remaining_segments {
0 => (ty, res),
1 => {
// resolve unselected assoc types
@@ -137,7 +162,7 @@
}
_ => {
// FIXME report error (ambiguous associated type)
- (TyKind::Error.intern(Interner), None)
+ (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None)
}
}
}
@@ -147,8 +172,11 @@
&mut self,
resolution: TypeNs,
infer_args: bool,
- ) -> (Ty, Option<TypeNs>) {
+ ) -> (Ty<'db>, Option<TypeNs>) {
let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
+ tracing::debug!(?remaining_segments);
+ let rem_seg_len = remaining_segments.len();
+ tracing::debug!(?rem_seg_len);
let ty = match resolution {
TypeNs::TraitId(trait_) => {
@@ -156,15 +184,17 @@
1 => {
let trait_ref = self.lower_trait_ref_from_resolved_path(
trait_,
- TyKind::Error.intern(Interner),
- infer_args,
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed),
+ false,
);
-
+ tracing::debug!(?trait_ref);
self.skip_resolved_segment();
let segment = self.current_or_prev_segment;
+ let trait_id = trait_ref.def_id.0;
let found =
- trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name);
+ trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
+ tracing::debug!(?found);
match found {
Some(associated_ty) => {
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
@@ -173,27 +203,30 @@
// this point (`trait_ref.substitution`).
let substitution = self.substs_from_path_segment(
associated_ty.into(),
- infer_args,
+ false,
None,
true,
);
- let substitution = Substitution::from_iter(
- Interner,
- trait_ref.substitution.iter(Interner).chain(
- substitution
- .iter(Interner)
- .skip(trait_ref.substitution.len(Interner)),
- ),
+ let args = GenericArgs::new_from_iter(
+ self.ctx.interner,
+ trait_ref
+ .args
+ .iter()
+ .chain(substitution.iter().skip(trait_ref.args.len())),
);
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution,
- }))
- .intern(Interner)
+ Ty::new_alias(
+ self.ctx.interner,
+ AliasTyKind::Projection,
+ AliasTy::new_from_args(
+ self.ctx.interner,
+ associated_ty.into(),
+ args,
+ ),
+ )
}
None => {
// FIXME: report error (associated type not found)
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
}
}
}
@@ -201,73 +234,34 @@
// Trait object type without dyn; this should be handled in upstream. See
// `lower_path()`.
stdx::never!("unexpected fully resolved trait path");
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
}
_ => {
// FIXME report error (ambiguous associated type)
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
}
};
return (ty, None);
}
- TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode {
- ParamLoweringMode::Placeholder => {
- let generics = self.ctx.generics();
- let idx = generics.type_or_const_param_idx(param_id.into()).unwrap();
- TyKind::Placeholder(to_placeholder_idx(
- self.ctx.db,
- param_id.into(),
- idx as u32,
- ))
- }
- ParamLoweringMode::Variable => {
- let idx = match self.ctx.generics().type_or_const_param_idx(param_id.into()) {
- None => {
- never!("no matching generics");
- return (TyKind::Error.intern(Interner), None);
- }
- Some(idx) => idx,
- };
-
- TyKind::BoundVar(BoundVar::new(self.ctx.in_binders, idx))
- }
- }
- .intern(Interner),
- TypeNs::SelfType(impl_id) => {
+ TypeNs::GenericParam(param_id) => {
let generics = self.ctx.generics();
-
- match self.ctx.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // `def` can be either impl itself or item within, and we need impl itself
- // now.
- let generics = generics.parent_or_self();
- let interner = DbInterner::new_with(self.ctx.db, None, None);
- let subst = generics.placeholder_subst(self.ctx.db);
- let args: crate::next_solver::GenericArgs<'_> =
- subst.to_nextsolver(interner);
- self.ctx
- .db
- .impl_self_ty(impl_id)
- .instantiate(interner, args)
- .to_chalk(interner)
+ let idx = generics.type_or_const_param_idx(param_id.into());
+ match idx {
+ None => {
+ never!("no matching generics");
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
}
- ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id)
- .fill_with_bound_vars(self.ctx.in_binders, 0)
- .build(DbInterner::conjure())
- .to_chalk(DbInterner::conjure()),
+ Some(idx) => {
+ let (pidx, _param) = generics.iter().nth(idx).unwrap();
+ assert_eq!(pidx, param_id.into());
+ self.ctx.type_param(param_id, idx as u32)
+ }
}
}
+ TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
TypeNs::AdtSelfType(adt) => {
- let generics = generics(self.ctx.db, adt.into());
- let substs = match self.ctx.type_param_mode {
- ParamLoweringMode::Placeholder => generics.placeholder_subst(self.ctx.db),
- ParamLoweringMode::Variable => {
- generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
- }
- };
- let interner = DbInterner::conjure();
- let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
- self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner)
+ let args = GenericArgs::identity_for_item(self.ctx.interner, adt.into());
+ Ty::new_adt(self.ctx.interner, adt, args)
}
TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
@@ -275,15 +269,19 @@
TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
// FIXME: report error
TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
- return (TyKind::Error.intern(Interner), None);
+ return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
}
};
+ tracing::debug!(?ty);
+
self.skip_resolved_segment();
self.lower_ty_relative_path(ty, Some(resolution), infer_args)
}
- fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
+ /// This returns whether to keep the resolution (`true`) of throw it (`false`).
+ #[must_use]
+ fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) -> bool {
let mut prohibit_generics_on_resolved = |reason| {
if self.current_or_prev_segment.args_and_bindings.is_some() {
let segment = self.current_segment_u32();
@@ -302,7 +300,13 @@
prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
}
TypeNs::AdtSelfType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
+
+ if self.ctx.lowering_param_default.is_some() {
+ // Generic defaults are not allowed to refer to `Self`.
+ // FIXME: Emit an error.
+ return false;
+ }
}
TypeNs::BuiltinType(_) => {
prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
@@ -315,6 +319,8 @@
| TypeNs::TypeAliasId(_)
| TypeNs::TraitId(_) => {}
}
+
+ true
}
pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
@@ -325,6 +331,7 @@
Some(res)
}
+ #[tracing::instrument(skip(self), ret)]
pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
let (resolution, remaining_index, _, prefix_info) =
self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?;
@@ -347,11 +354,6 @@
self.current_or_prev_segment =
segments.get(resolved_segment_idx).expect("should have resolved segment");
- if matches!(self.path, Path::BarePath(..)) {
- // Bare paths cannot have generics, so skip them as an optimization.
- return Some((resolution, remaining_index));
- }
-
for (i, mod_segment) in module_segments.iter().enumerate() {
if mod_segment.args_and_bindings.is_some() {
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
@@ -371,87 +373,233 @@
});
}
- self.handle_type_ns_resolution(&resolution);
+ if !self.handle_type_ns_resolution(&resolution) {
+ return None;
+ }
Some((resolution, remaining_index))
}
- fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty {
- let Some(res) = res else {
- return TyKind::Error.intern(Interner);
- };
- let segment = self.current_or_prev_segment;
- let ty = named_associated_type_shorthand_candidates(
+ pub(crate) fn resolve_path_in_value_ns(
+ &mut self,
+ hygiene_id: HygieneId,
+ ) -> Option<ResolveValueResult> {
+ let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
self.ctx.db,
- self.ctx.def,
- res,
- Some(segment.name.clone()),
- move |name, t, associated_ty| {
- if name != segment.name {
- return None;
- }
- let generics = self.ctx.generics();
+ self.path,
+ hygiene_id,
+ )?;
- let parent_subst = t.substitution.clone();
- let parent_subst = match self.ctx.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put them in now.
- let s = generics.placeholder_subst(self.ctx.db);
- s.apply(parent_subst, Interner)
- }
- ParamLoweringMode::Variable => {
- // We need to shift in the bound vars, since
- // `named_associated_type_shorthand_candidates` does not do that.
- parent_subst.shifted_in_from(Interner, self.ctx.in_binders)
+ let segments = self.segments;
+ if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+ // `segments.is_empty()` can occur with `self`.
+ return Some(res);
+ }
+
+ let (mod_segments, enum_segment, resolved_segment_idx) = match res {
+ ResolveValueResult::Partial(_, unresolved_segment, _) => {
+ (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
+ }
+ ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
+ if prefix_info.enum_variant =>
+ {
+ (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
+ }
+ ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
+ };
+
+ self.current_segment_idx = resolved_segment_idx;
+ self.current_or_prev_segment =
+ segments.get(resolved_segment_idx).expect("should have resolved segment");
+
+ for (i, mod_segment) in mod_segments.iter().enumerate() {
+ if mod_segment.args_and_bindings.is_some() {
+ self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+ segment: i as u32,
+ reason: GenericArgsProhibitedReason::Module,
+ });
+ }
+ }
+
+ if let Some(enum_segment) = enum_segment
+ && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+ && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+ {
+ self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+ segment: (enum_segment + 1) as u32,
+ reason: GenericArgsProhibitedReason::EnumVariant,
+ });
+ }
+
+ match &res {
+ ResolveValueResult::ValueNs(resolution, _) => {
+ let resolved_segment_idx = self.current_segment_u32();
+ let resolved_segment = self.current_or_prev_segment;
+
+ let mut prohibit_generics_on_resolved = |reason| {
+ if resolved_segment.args_and_bindings.is_some() {
+ self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+ segment: resolved_segment_idx,
+ reason,
+ });
}
};
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`t.substitution`).
- let substs =
- self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
-
- let substs = Substitution::from_iter(
- Interner,
- parent_subst
- .iter(Interner)
- .chain(substs.iter(Interner).skip(parent_subst.len(Interner))),
- );
-
- Some(
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: substs,
- }))
- .intern(Interner),
- )
- },
- );
-
- ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
+ match resolution {
+ ValueNs::ImplSelf(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
+ }
+ // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
+ // E0109 (generic arguments provided for a type that doesn't accept them) for
+ // consts and statics, presumably as a defense against future in which consts
+ // and statics can be generic, or just because it was easier for rustc implementors.
+ // That means we'll show the wrong error code. Because of us it's easier to do it
+ // this way :)
+ ValueNs::GenericParam(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
+ }
+ ValueNs::StaticId(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
+ }
+ ValueNs::LocalBinding(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
+ }
+ ValueNs::FunctionId(_)
+ | ValueNs::StructId(_)
+ | ValueNs::EnumVariantId(_)
+ | ValueNs::ConstId(_) => {}
+ }
+ }
+ ResolveValueResult::Partial(resolution, _, _) => {
+ if !self.handle_type_ns_resolution(resolution) {
+ return None;
+ }
+ }
+ };
+ Some(res)
}
- fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty {
+ #[tracing::instrument(skip(self), ret)]
+ fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
+ let interner = self.ctx.interner;
+ let Some(res) = res else {
+ return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
+ };
+ let def = self.ctx.def;
+ let segment = self.current_or_prev_segment;
+ let assoc_name = segment.name;
+ let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
+ if name != assoc_name {
+ return None;
+ }
+
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`t.substitution`).
+ let substs =
+ self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
+
+ let substs = GenericArgs::new_from_iter(
+ interner,
+ t.args.iter().chain(substs.iter().skip(t.args.len())),
+ );
+
+ Some(Ty::new_alias(
+ interner,
+ AliasTyKind::Projection,
+ AliasTy::new(interner, associated_ty.into(), substs),
+ ))
+ };
+ named_associated_type_shorthand_candidates(
+ interner,
+ def,
+ res,
+ Some(assoc_name.clone()),
+ check_alias,
+ )
+ .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
+ }
+
+ fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
let generic_def = match typeable {
- TyDefId::BuiltinType(builtin) => return TyBuilder::builtin(builtin),
+ TyDefId::BuiltinType(builtinty) => {
+ return Ty::from_builtin_type(self.ctx.interner, builtinty);
+ }
TyDefId::AdtId(it) => it.into(),
TyDefId::TypeAliasId(it) => it.into(),
};
- let substs = self.substs_from_path_segment(generic_def, infer_args, None, false);
- let interner = DbInterner::conjure();
- let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
- self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner)
+ let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
+ let ty = ty_query(self.ctx.db, typeable);
+ ty.instantiate(self.ctx.interner, args)
+ }
+
+ /// Collect generic arguments from a path into a `Substs`. See also
+ /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
+ pub(crate) fn substs_from_path(
+ &mut self,
+ // Note that we don't call `db.value_type(resolved)` here,
+ // `ValueTyDefId` is just a convenient way to pass generics and
+ // special-case enum variants
+ resolved: ValueTyDefId,
+ infer_args: bool,
+ lowering_assoc_type_generics: bool,
+ ) -> GenericArgs<'db> {
+ let interner = self.ctx.interner;
+ let prev_current_segment_idx = self.current_segment_idx;
+ let prev_current_segment = self.current_or_prev_segment;
+
+ let generic_def = match resolved {
+ ValueTyDefId::FunctionId(it) => it.into(),
+ ValueTyDefId::StructId(it) => it.into(),
+ ValueTyDefId::UnionId(it) => it.into(),
+ ValueTyDefId::ConstId(it) => it.into(),
+ ValueTyDefId::StaticId(_) => {
+ return GenericArgs::new_from_iter(interner, []);
+ }
+ ValueTyDefId::EnumVariantId(var) => {
+ // the generic args for an enum variant may be either specified
+ // on the segment referring to the enum, or on the segment
+ // referring to the variant. So `Option::<T>::None` and
+ // `Option::None::<T>` are both allowed (though the former is
+ // FIXME: This isn't strictly correct, enum variants may be used not through the enum
+ // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
+ // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
+ // if generics exist on the module and they don't match with the variant.
+ // preferred). See also `def_ids_for_path_segments` in rustc.
+ //
+ // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
+ // This simplifies the code a bit.
+ let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
+ let penultimate = self.segments.get(penultimate_idx);
+ if let Some(penultimate) = penultimate
+ && self.current_or_prev_segment.args_and_bindings.is_none()
+ && penultimate.args_and_bindings.is_some()
+ {
+ self.current_segment_idx = penultimate_idx;
+ self.current_or_prev_segment = penultimate;
+ }
+ var.lookup(self.ctx.db).parent.into()
+ }
+ };
+ let result = self.substs_from_path_segment(
+ generic_def,
+ infer_args,
+ None,
+ lowering_assoc_type_generics,
+ );
+ self.current_segment_idx = prev_current_segment_idx;
+ self.current_or_prev_segment = prev_current_segment;
+ result
}
pub(crate) fn substs_from_path_segment(
&mut self,
def: GenericDefId,
infer_args: bool,
- explicit_self_ty: Option<Ty>,
+ explicit_self_ty: Option<Ty<'db>>,
lowering_assoc_type_generics: bool,
- ) -> Substitution {
+ ) -> GenericArgs<'db> {
let old_lifetime_elision = self.ctx.lifetime_elision.clone();
if let Some(args) = self.current_or_prev_segment.args_and_bindings
@@ -478,7 +626,7 @@
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
);
- return TyBuilder::unknown_subst(self.ctx.db, def);
+ return unknown_subst(self.ctx.interner, def);
}
// `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
@@ -501,20 +649,20 @@
pub(super) fn substs_from_args_and_bindings(
&mut self,
- args_and_bindings: Option<&GenericArgs>,
+ args_and_bindings: Option<&HirGenericArgs>,
def: GenericDefId,
infer_args: bool,
- explicit_self_ty: Option<Ty>,
+ explicit_self_ty: Option<Ty<'db>>,
generics_source: PathGenericsSource,
lowering_assoc_type_generics: bool,
- lifetime_elision: LifetimeElisionKind,
- ) -> Substitution {
- struct LowererCtx<'a, 'b, 'c> {
- ctx: &'a mut PathLoweringContext<'b, 'c>,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ ) -> GenericArgs<'db> {
+ struct LowererCtx<'a, 'b, 'c, 'db> {
+ ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
generics_source: PathGenericsSource,
}
- impl GenericArgsLowerer for LowererCtx<'_, '_, '_> {
+ impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
fn report_len_mismatch(
&mut self,
def: GenericDefId,
@@ -549,23 +697,24 @@
&mut self,
param_id: GenericParamId,
param: GenericParamDataRef<'_>,
- arg: &GenericArg,
- ) -> crate::GenericArg {
- match (param, arg) {
- (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
- self.ctx.ctx.lower_lifetime(*lifetime).cast(Interner)
+ arg: &HirGenericArg,
+ ) -> GenericArg<'db> {
+ match (param, *arg) {
+ (
+ GenericParamDataRef::LifetimeParamData(_),
+ HirGenericArg::Lifetime(lifetime),
+ ) => self.ctx.ctx.lower_lifetime(lifetime).into(),
+ (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
+ self.ctx.ctx.lower_ty(type_ref).into()
}
- (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
- self.ctx.ctx.lower_ty(*type_ref).cast(Interner)
- }
- (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
+ (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
let GenericParamId::ConstParamId(const_id) = param_id else {
unreachable!("non-const param ID for const param");
};
self.ctx
.ctx
- .lower_const(konst, self.ctx.ctx.db.const_param_ty(const_id))
- .cast(Interner)
+ .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
+ .into()
}
_ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
}
@@ -573,9 +722,9 @@
fn provided_type_like_const(
&mut self,
- const_ty: Ty,
+ const_ty: Ty<'db>,
arg: TypeLikeConst<'_>,
- ) -> crate::Const {
+ ) -> Const<'db> {
match arg {
TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
TypeLikeConst::Infer => unknown_const(const_ty),
@@ -588,18 +737,19 @@
param_id: GenericParamId,
param: GenericParamDataRef<'_>,
infer_args: bool,
- preceding_args: &[crate::GenericArg],
- ) -> crate::GenericArg {
- let default = || {
- self.ctx
- .ctx
- .db
- .generic_defaults(def)
- .get(preceding_args.len())
- .map(|default| default.clone().substitute(Interner, preceding_args))
- };
+ preceding_args: &[GenericArg<'db>],
+ ) -> GenericArg<'db> {
+ let default =
+ || {
+ self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(
+ |default| default.instantiate(self.ctx.ctx.interner, preceding_args),
+ )
+ };
match param {
- GenericParamDataRef::LifetimeParamData(_) => error_lifetime().cast(Interner),
+ GenericParamDataRef::LifetimeParamData(_) => {
+ Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+ .into()
+ }
GenericParamDataRef::TypeParamData(param) => {
if !infer_args
&& param.default.is_some()
@@ -607,7 +757,7 @@
{
return default;
}
- TyKind::Error.intern(Interner).cast(Interner)
+ Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
}
GenericParamDataRef::ConstParamData(param) => {
if !infer_args
@@ -619,19 +769,23 @@
let GenericParamId::ConstParamId(const_id) = param_id else {
unreachable!("non-const param ID for const param");
};
- unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id))
- .cast(Interner)
+ unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
}
}
}
- fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg {
+ fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db> {
match param_id {
- GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
- GenericParamId::ConstParamId(const_id) => {
- unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id))
+ GenericParamId::TypeParamId(_) => {
+ Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
}
- GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
+ GenericParamId::ConstParamId(const_id) => {
+ unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
+ }
+ GenericParamId::LifetimeParamId(_) => {
+ Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+ .into()
+ }
}
}
@@ -649,6 +803,14 @@
});
}
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ });
+ }
+
fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
generics_source: self.generics_source,
@@ -674,38 +836,39 @@
pub(crate) fn lower_trait_ref_from_resolved_path(
&mut self,
resolved: TraitId,
- explicit_self_ty: Ty,
+ explicit_self_ty: Ty<'db>,
infer_args: bool,
- ) -> TraitRef {
- let substs = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
- TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
+ ) -> TraitRef<'db> {
+ let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
+ TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
}
fn trait_ref_substs_from_path(
&mut self,
resolved: TraitId,
- explicit_self_ty: Ty,
+ explicit_self_ty: Ty<'db>,
infer_args: bool,
- ) -> Substitution {
+ ) -> GenericArgs<'db> {
self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
}
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
mut self,
- trait_ref: TraitRef,
- ) -> Option<impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b, 'c>> {
+ trait_ref: TraitRef<'db>,
+ ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
+ let interner = self.ctx.interner;
self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
let found = associated_type_by_name_including_super_traits(
self.ctx.db,
- trait_ref.clone(),
+ trait_ref,
&binding.name,
);
let (super_trait_ref, associated_ty) = match found {
None => return SmallVec::new(),
Some(t) => t,
};
- let substitution =
+ let args =
self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
// generic params. It's inefficient to splice the `Substitution`s, so we may want
@@ -715,7 +878,7 @@
binding.args.as_ref(),
associated_ty.into(),
false, // this is not relevant
- Some(super_trait_ref.self_type_parameter(Interner)),
+ Some(super_trait_ref.self_ty()),
PathGenericsSource::AssocType {
segment: this.current_segment_u32(),
assoc_type: binding_idx as u32,
@@ -724,27 +887,20 @@
this.ctx.lifetime_elision.clone(),
)
});
- let substitution = Substitution::from_iter(
- Interner,
- super_trait_ref.substitution.iter(Interner).chain(
- substitution
- .iter(Interner)
- .skip(super_trait_ref.substitution.len(Interner)),
- ),
+ let args = GenericArgs::new_from_iter(
+ interner,
+ super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
);
- let projection_ty = ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution,
- };
+ let projection_term =
+ AliasTerm::new_from_args(interner, associated_ty.into(), args);
let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
-
if let Some(type_ref) = binding.type_ref {
let lifetime_elision =
if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
// `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
- LifetimeElisionKind::for_fn_ret()
+ LifetimeElisionKind::for_fn_ret(self.ctx.interner)
} else {
self.ctx.lifetime_elision.clone()
};
@@ -756,31 +912,33 @@
ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
) => {
let ty = this.ctx.lower_ty(type_ref);
- let alias_eq = AliasEq {
- alias: AliasTy::Projection(projection_ty.clone()),
- ty,
- };
- predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(
- alias_eq,
- )));
+ let pred = Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Projection(
+ ProjectionPredicate {
+ projection_term,
+ term: ty.into(),
+ },
+ ),
+ )),
+ ));
+ predicates.push(pred);
}
}
- });
+ })
}
-
- self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
- for bound in binding.bounds.iter() {
- predicates.extend(
- this.ctx.lower_type_bound(
- bound,
- TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
- .intern(Interner),
- false,
- ),
- );
- }
- });
-
+ for bound in binding.bounds.iter() {
+ predicates.extend(self.ctx.lower_type_bound(
+ bound,
+ Ty::new_alias(
+ self.ctx.interner,
+ AliasTyKind::Projection,
+ AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
+ ),
+ false,
+ ));
+ }
predicates
})
})
@@ -793,7 +951,7 @@
Path(&'a Path),
}
-pub(crate) trait GenericArgsLowerer {
+pub(crate) trait GenericArgsLowerer<'db> {
fn report_elided_lifetimes_in_path(
&mut self,
def: GenericDefId,
@@ -801,6 +959,8 @@
hard_error: bool,
);
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
+
fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
fn report_len_mismatch(
@@ -817,10 +977,11 @@
&mut self,
param_id: GenericParamId,
param: GenericParamDataRef<'_>,
- arg: &GenericArg,
- ) -> crate::GenericArg;
+ arg: &HirGenericArg,
+ ) -> GenericArg<'db>;
- fn provided_type_like_const(&mut self, const_ty: Ty, arg: TypeLikeConst<'_>) -> crate::Const;
+ fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
+ -> Const<'db>;
fn inferred_kind(
&mut self,
@@ -828,21 +989,21 @@
param_id: GenericParamId,
param: GenericParamDataRef<'_>,
infer_args: bool,
- preceding_args: &[crate::GenericArg],
- ) -> crate::GenericArg;
+ preceding_args: &[GenericArg<'db>],
+ ) -> GenericArg<'db>;
- fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg;
+ fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db>;
}
/// Returns true if there was an error.
-fn check_generic_args_len(
- args_and_bindings: Option<&GenericArgs>,
+fn check_generic_args_len<'db>(
+ args_and_bindings: Option<&HirGenericArgs>,
def: GenericDefId,
def_generics: &Generics,
infer_args: bool,
- lifetime_elision: &LifetimeElisionKind,
+ lifetime_elision: &LifetimeElisionKind<'db>,
lowering_assoc_type_generics: bool,
- ctx: &mut impl GenericArgsLowerer,
+ ctx: &mut impl GenericArgsLowerer<'db>,
) -> bool {
let mut had_error = false;
@@ -851,8 +1012,10 @@
let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
for arg in args_no_self {
match arg {
- GenericArg::Lifetime(_) => provided_lifetimes_count += 1,
- GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1,
+ HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1,
+ HirGenericArg::Type(_) | HirGenericArg::Const(_) => {
+ provided_types_and_consts_count += 1
+ }
}
}
}
@@ -873,6 +1036,13 @@
ctx.report_missing_lifetime(def, lifetime_args_len as u32);
had_error = true
}
+ LifetimeElisionKind::ElisionFailure => {
+ ctx.report_elision_failure(def, lifetime_args_len as u32);
+ had_error = true;
+ }
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ // FIXME: Check there are other lifetimes in scope, and error/lint.
+ }
LifetimeElisionKind::Elided(_) => {
ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
}
@@ -919,17 +1089,21 @@
had_error
}
-pub(crate) fn substs_from_args_and_bindings(
- db: &dyn HirDatabase,
+pub(crate) fn substs_from_args_and_bindings<'db>(
+ db: &'db dyn HirDatabase,
store: &ExpressionStore,
- args_and_bindings: Option<&GenericArgs>,
+ args_and_bindings: Option<&HirGenericArgs>,
def: GenericDefId,
mut infer_args: bool,
- lifetime_elision: LifetimeElisionKind,
+ lifetime_elision: LifetimeElisionKind<'db>,
lowering_assoc_type_generics: bool,
- explicit_self_ty: Option<Ty>,
- ctx: &mut impl GenericArgsLowerer,
-) -> Substitution {
+ explicit_self_ty: Option<Ty<'db>>,
+ ctx: &mut impl GenericArgsLowerer<'db>,
+) -> GenericArgs<'db> {
+ let interner = DbInterner::new_with(db, None, None);
+
+ tracing::debug!(?args_and_bindings);
+
// Order is
// - Parent parameters
// - Optional Self parameter
@@ -940,7 +1114,7 @@
// We do not allow inference if there are specified args, i.e. we do not allow partial inference.
let has_non_lifetime_args =
- args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
+ args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_)));
infer_args &= !has_non_lifetime_args;
let had_count_error = check_generic_args_len(
@@ -981,7 +1155,7 @@
let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
ctx.provided_kind(self_param_id, self_param, self_ty)
} else {
- explicit_self_ty.map(|it| it.cast(Interner)).unwrap_or_else(|| {
+ explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
})
};
@@ -996,7 +1170,7 @@
// input. We try to handle both sensibly.
match (args.peek(), params.peek()) {
(Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
- (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
+ (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
{
// Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
@@ -1004,15 +1178,15 @@
substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
params.next();
}
- (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
- | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
- | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
+ (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
+ | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
+ | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
substs.push(ctx.provided_kind(param_id, param, arg));
args.next();
params.next();
}
(
- GenericArg::Type(_) | GenericArg::Const(_),
+ HirGenericArg::Type(_) | HirGenericArg::Const(_),
GenericParamDataRef::LifetimeParamData(_),
) => {
// We expected a lifetime argument, but got a type or const
@@ -1021,13 +1195,13 @@
params.next();
force_infer_lt = Some((arg_idx as u32, param_id));
}
- (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
+ (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
if let Some(konst) = type_looks_like_const(store, *type_ref) {
let GenericParamId::ConstParamId(param_id) = param_id else {
panic!("unmatching param kinds");
};
- let const_ty = db.const_param_ty(param_id);
- substs.push(ctx.provided_type_like_const(const_ty, konst).cast(Interner));
+ let const_ty = const_param_ty_query(db, param_id);
+ substs.push(ctx.provided_type_like_const(const_ty, konst).into());
args.next();
params.next();
} else {
@@ -1066,7 +1240,7 @@
// after a type or const). We want to throw an error in this case.
if !had_count_error {
assert!(
- matches!(arg, GenericArg::Lifetime(_)),
+ matches!(arg, HirGenericArg::Lifetime(_)),
"the only possible situation here is incorrect lifetime order"
);
let (provided_arg_idx, param_id) =
@@ -1081,12 +1255,16 @@
// If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
let param = if let GenericParamId::LifetimeParamId(_) = param_id {
match &lifetime_elision {
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
+ LifetimeElisionKind::ElisionFailure
+ | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
| LifetimeElisionKind::AnonymousReportError => {
assert!(had_count_error);
ctx.inferred_kind(def, param_id, param, infer_args, &substs)
}
- LifetimeElisionKind::Elided(lifetime) => lifetime.clone().cast(Interner),
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ Region::new_static(interner).into()
+ }
+ LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
| LifetimeElisionKind::Infer => {
// FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
@@ -1105,7 +1283,7 @@
}
}
- Substitution::from_iter(Interner, substs)
+ GenericArgs::new_from_iter(interner, substs)
}
fn type_looks_like_const(
@@ -1124,3 +1302,17 @@
_ => None,
}
}
+
+fn unknown_subst<'db>(interner: DbInterner<'db>, def: impl Into<GenericDefId>) -> GenericArgs<'db> {
+ let params = generics(interner.db(), def.into());
+ GenericArgs::new_from_iter(
+ interner,
+ params.iter_id().map(|id| match id {
+ GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
+ GenericParamId::ConstParamId(id) => {
+ unknown_const_as_generic(const_param_ty_query(interner.db(), id))
+ }
+ GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
+ }),
+ )
+}
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs
deleted file mode 100644
index abca6b6..0000000
--- a/crates/hir-ty/src/lower_nextsolver.rs
+++ /dev/null
@@ -1,2220 +0,0 @@
-//! Methods for lowering the HIR to types. There are two main cases here:
-//!
-//! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-//! type: The entry point for this is `TyLoweringContext::lower_ty`.
-//! - Building the type for an item: This happens through the `ty` query.
-//!
-//! This usually involves resolving names, collecting generic arguments etc.
-#![allow(unused)]
-// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir
-pub(crate) mod path;
-
-use std::{
- cell::OnceCell,
- iter, mem,
- ops::{self, Deref, Not as _},
-};
-
-use base_db::Crate;
-use either::Either;
-use hir_def::hir::generics::GenericParamDataRef;
-use hir_def::item_tree::FieldsShape;
-use hir_def::{
- AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
- GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup,
- StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId,
- expr_store::{
- ExpressionStore,
- path::{GenericArg, Path},
- },
- hir::generics::{TypeOrConstParamData, WherePredicate},
- lang_item::LangItem,
- resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
- signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
- type_ref::{
- ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
- TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
- },
-};
-use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId};
-use hir_expand::name::Name;
-use intern::{Symbol, sym};
-use la_arena::{Arena, ArenaMap, Idx};
-use path::{PathDiagnosticCallback, PathLoweringContext};
-use rustc_ast_ir::Mutability;
-use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::Captures;
-use rustc_type_ir::{
- AliasTyKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection,
- ExistentialTraitRef, FnSig, OutlivesPredicate,
- TyKind::{self},
- TypeVisitableExt,
- inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _},
-};
-use rustc_type_ir::{TypeFoldable, TypeFolder, Upcast};
-use salsa::plumbing::AsId;
-use smallvec::{SmallVec, smallvec};
-use stdx::never;
-use triomphe::Arc;
-
-use crate::ValueTyDefId;
-use crate::next_solver::ParamConst;
-use crate::{
- FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
- TyLoweringDiagnosticKind,
- consteval::{intern_const_ref, path_to_const, unknown_const_as_generic},
- db::HirDatabase,
- generics::{Generics, generics, trait_self_param_idx},
- lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics},
- next_solver::{
- AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind,
- BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder,
- EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region,
- SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
- abi::Safety,
- mapping::{ChalkToNextSolver, convert_ty_for_result},
- },
-};
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTraits<'db> {
- pub(crate) impl_traits: Arena<ImplTrait<'db>>,
-}
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTrait<'db> {
- pub(crate) predicates: Vec<Clause<'db>>,
-}
-
-pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>;
-
-#[derive(Debug, Default)]
-struct ImplTraitLoweringState<'db> {
- /// When turning `impl Trait` into opaque types, we have to collect the
- /// bounds at the same time to get the IDs correct (without becoming too
- /// complicated).
- mode: ImplTraitLoweringMode,
- // This is structured as a struct with fields and not as an enum because it helps with the borrow checker.
- opaque_type_data: Arena<ImplTrait<'db>>,
- param_and_variable_counter: u16,
-}
-impl<'db> ImplTraitLoweringState<'db> {
- fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> {
- Self { mode, opaque_type_data: Arena::new(), param_and_variable_counter: 0 }
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum LifetimeElisionKind<'db> {
- /// Create a new anonymous lifetime parameter and reference it.
- ///
- /// If `report_in_path`, report an error when encountering lifetime elision in a path:
- /// ```compile_fail
- /// struct Foo<'a> { x: &'a () }
- /// async fn foo(x: Foo) {}
- /// ```
- ///
- /// Note: the error should not trigger when the elided lifetime is in a pattern or
- /// expression-position path:
- /// ```
- /// struct Foo<'a> { x: &'a () }
- /// async fn foo(Foo { x: _ }: Foo<'_>) {}
- /// ```
- AnonymousCreateParameter { report_in_path: bool },
-
- /// Replace all anonymous lifetimes by provided lifetime.
- Elided(Region<'db>),
-
- /// Give a hard error when either `&` or `'_` is written. Used to
- /// rule out things like `where T: Foo<'_>`. Does not imply an
- /// error on default object bounds (e.g., `Box<dyn Foo>`).
- AnonymousReportError,
-
- /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
- /// otherwise give a warning that the previous behavior of introducing a new early-bound
- /// lifetime is a bug and will be removed (if `only_lint` is enabled).
- StaticIfNoLifetimeInScope { only_lint: bool },
-
- /// Signal we cannot find which should be the anonymous lifetime.
- ElisionFailure,
-
- /// Infer all elided lifetimes.
- Infer,
-}
-
-impl<'db> LifetimeElisionKind<'db> {
- #[inline]
- pub(crate) fn for_const(
- interner: DbInterner<'db>,
- const_parent: ItemContainerId,
- ) -> LifetimeElisionKind<'db> {
- match const_parent {
- ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
- LifetimeElisionKind::Elided(Region::new_static(interner))
- }
- ItemContainerId::ImplId(_) => {
- LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
- }
- ItemContainerId::TraitId(_) => {
- LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false }
- }
- }
- }
-
- #[inline]
- pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> {
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
- }
-
- #[inline]
- pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> {
- // FIXME: We should use the elided lifetime here, or `ElisionFailure`.
- LifetimeElisionKind::Elided(Region::error(interner))
- }
-}
-
-#[derive(Debug)]
-pub struct TyLoweringContext<'db, 'a> {
- pub db: &'db dyn HirDatabase,
- interner: DbInterner<'db>,
- resolver: &'a Resolver<'db>,
- store: &'a ExpressionStore,
- def: GenericDefId,
- generics: OnceCell<Generics>,
- in_binders: DebruijnIndex,
- impl_trait_mode: ImplTraitLoweringState<'db>,
- /// Tracks types with explicit `?Sized` bounds.
- pub(crate) unsized_types: FxHashSet<Ty<'db>>,
- pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
- lifetime_elision: LifetimeElisionKind<'db>,
- /// We disallow referencing generic parameters that have an index greater than or equal to this number.
- disallow_params_after: u32,
-}
-
-impl<'db, 'a> TyLoweringContext<'db, 'a> {
- pub fn new(
- db: &'db dyn HirDatabase,
- resolver: &'a Resolver<'db>,
- store: &'a ExpressionStore,
- def: GenericDefId,
- lifetime_elision: LifetimeElisionKind<'db>,
- ) -> Self {
- let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
- let in_binders = DebruijnIndex::ZERO;
- Self {
- db,
- interner: DbInterner::new_with(db, Some(resolver.krate()), None),
- resolver,
- def,
- generics: Default::default(),
- store,
- in_binders,
- impl_trait_mode,
- unsized_types: FxHashSet::default(),
- diagnostics: Vec::new(),
- lifetime_elision,
- disallow_params_after: u32::MAX,
- }
- }
-
- pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) {
- self.lifetime_elision = lifetime_elision;
- }
-
- pub(crate) fn with_debruijn<T>(
- &mut self,
- debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
- ) -> T {
- let old_debruijn = mem::replace(&mut self.in_binders, debruijn);
- let result = f(self);
- self.in_binders = old_debruijn;
- result
- }
-
- pub(crate) fn with_shifted_in<T>(
- &mut self,
- debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
- ) -> T {
- self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f)
- }
-
- pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
- Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
- }
-
- pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
- self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
- self
- }
-
- pub(crate) fn disallow_params_after(&mut self, after: u32) {
- self.disallow_params_after = after;
- }
-
- pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
- self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind });
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub(crate) enum ImplTraitLoweringMode {
- /// `impl Trait` gets lowered into an opaque type that doesn't unify with
- /// anything except itself. This is used in places where values flow 'out',
- /// i.e. for arguments of the function we're currently checking, and return
- /// types of functions we're calling.
- Opaque,
- /// `impl Trait` is disallowed and will be an error.
- #[default]
- Disallowed,
-}
-
-impl<'db, 'a> TyLoweringContext<'db, 'a> {
- pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
- self.lower_ty_ext(type_ref).0
- }
-
- pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
- let const_ref = &self.store[const_ref.expr];
- match const_ref {
- hir_def::hir::Expr::Path(path) => {
- path_to_const(self.db, self.resolver, path, || self.generics(), const_type)
- .unwrap_or_else(|| unknown_const(const_type))
- }
- hir_def::hir::Expr::Literal(literal) => intern_const_ref(
- self.db,
- &match *literal {
- hir_def::hir::Literal::Float(_, _)
- | hir_def::hir::Literal::String(_)
- | hir_def::hir::Literal::ByteString(_)
- | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown,
- hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c),
- hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b),
- hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val),
- hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val),
- },
- const_type,
- self.resolver.krate(),
- ),
- hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => {
- if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] {
- // Only handle negation for signed integers and floats
- match literal {
- hir_def::hir::Literal::Int(_, _) | hir_def::hir::Literal::Float(_, _) => {
- if let Some(negated_literal) = literal.clone().negate() {
- intern_const_ref(
- self.db,
- &negated_literal.into(),
- const_type,
- self.resolver.krate(),
- )
- } else {
- unknown_const(const_type)
- }
- }
- // For unsigned integers, chars, bools, etc., negation is not meaningful
- _ => unknown_const(const_type),
- }
- } else {
- unknown_const(const_type)
- }
- }
- _ => unknown_const(const_type),
- }
- }
-
- pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> {
- path_to_const(self.db, self.resolver, path, || self.generics(), const_type)
- .unwrap_or_else(|| unknown_const(const_type))
- }
-
- fn generics(&self) -> &Generics {
- self.generics.get_or_init(|| generics(self.db, self.def))
- }
-
- fn type_param(&mut self, id: TypeParamId, index: u32, name: Symbol) -> Ty<'db> {
- if index >= self.disallow_params_after {
- // FIXME: Report an error.
- Ty::new_error(self.interner, ErrorGuaranteed)
- } else {
- Ty::new_param(self.interner, id, index, name)
- }
- }
-
- fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
- if index >= self.disallow_params_after {
- // FIXME: Report an error.
- Const::error(self.interner)
- } else {
- Const::new_param(self.interner, ParamConst { id, index })
- }
- }
-
- fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
- if index >= self.disallow_params_after {
- // FIXME: Report an error.
- Region::error(self.interner)
- } else {
- Region::new_early_param(self.interner, EarlyParamRegion { id, index })
- }
- }
-
- #[tracing::instrument(skip(self), ret)]
- pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) {
- let interner = self.interner;
- let mut res = None;
- let type_ref = &self.store[type_ref_id];
- tracing::debug!(?type_ref);
- let ty = match type_ref {
- TypeRef::Never => Ty::new(interner, TyKind::Never),
- TypeRef::Tuple(inner) => {
- let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
- Ty::new_tup_from_iter(interner, inner_tys)
- }
- TypeRef::Path(path) => {
- let (ty, res_) =
- self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id));
- res = res_;
- ty
- }
- &TypeRef::TypeParam(type_param_id) => {
- res = Some(TypeNs::GenericParam(type_param_id));
-
- let generics = self.generics();
- let (idx, data) =
- generics.type_or_const_param(type_param_id.into()).expect("matching generics");
- let type_data = match data {
- TypeOrConstParamData::TypeParamData(ty) => ty,
- _ => unreachable!(),
- };
- self.type_param(
- type_param_id,
- idx as u32,
- type_data
- .name
- .as_ref()
- .map_or_else(|| sym::MISSING_NAME.clone(), |d| d.symbol().clone()),
- )
- }
- &TypeRef::RawPtr(inner, mutability) => {
- let inner_ty = self.lower_ty(inner);
- Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability)))
- }
- TypeRef::Array(array) => {
- let inner_ty = self.lower_ty(array.ty);
- let const_len = self.lower_const(array.len, Ty::new_usize(interner));
- Ty::new_array_with_const_len(interner, inner_ty, const_len)
- }
- &TypeRef::Slice(inner) => {
- let inner_ty = self.lower_ty(inner);
- Ty::new_slice(interner, inner_ty)
- }
- TypeRef::Reference(ref_) => {
- let inner_ty = self.lower_ty(ref_.ty);
- // FIXME: It should infer the eldided lifetimes instead of stubbing with error
- let lifetime = ref_
- .lifetime
- .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
- Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
- }
- TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
- TypeRef::Fn(fn_) => {
- let substs = self.with_shifted_in(
- DebruijnIndex::from_u32(1),
- |ctx: &mut TyLoweringContext<'_, '_>| {
- Tys::new_from_iter(
- interner,
- fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
- )
- },
- );
- Ty::new_fn_ptr(
- interner,
- Binder::dummy(FnSig {
- abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
- safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
- c_variadic: fn_.is_varargs,
- inputs_and_output: substs,
- }),
- )
- }
- TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
- TypeRef::ImplTrait(bounds) => {
- match self.impl_trait_mode.mode {
- ImplTraitLoweringMode::Opaque => {
- let origin = match self.resolver.generic_def() {
- Some(GenericDefId::FunctionId(it)) => Either::Left(it),
- Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
- _ => panic!(
- "opaque impl trait lowering must be in function or type alias"
- ),
- };
-
- // this dance is to make sure the data is in the right
- // place even if we encounter more opaque types while
- // lowering the bounds
- let idx = self
- .impl_trait_mode
- .opaque_type_data
- .alloc(ImplTrait { predicates: Vec::default() });
-
- // FIXME(next-solver): this from_raw/into_raw dance isn't nice, but it's minimal
- let impl_trait_id = origin.either(
- |f| ImplTraitId::ReturnTypeImplTrait(f, Idx::from_raw(idx.into_raw())),
- |a| ImplTraitId::TypeAliasImplTrait(a, Idx::from_raw(idx.into_raw())),
- );
- let opaque_ty_id: SolverDefId =
- self.db.intern_impl_trait_id(impl_trait_id).into();
-
- // We don't want to lower the bounds inside the binders
- // we're currently in, because they don't end up inside
- // those binders. E.g. when we have `impl Trait<impl
- // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
- // to the self parameter from `impl Trait`, and the
- // bounds aren't actually stored nested within each
- // other, but separately. So if the `T` refers to a type
- // parameter of the outer function, it's just one binder
- // away instead of two.
- let actual_opaque_type_data = self
- .with_debruijn(DebruijnIndex::ZERO, |ctx| {
- ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate())
- });
- self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data;
-
- let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id);
- Ty::new_alias(
- self.interner,
- AliasTyKind::Opaque,
- AliasTy::new_from_args(self.interner, opaque_ty_id, args),
- )
- }
- ImplTraitLoweringMode::Disallowed => {
- // FIXME: report error
- Ty::new_error(self.interner, ErrorGuaranteed)
- }
- }
- }
- TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
- };
- (ty, res)
- }
-
- /// This is only for `generic_predicates_for_param`, where we can't just
- /// lower the self types of the predicates since that could lead to cycles.
- /// So we just check here if the `type_ref` resolves to a generic param, and which.
- fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
- let type_ref = &self.store[type_ref];
- let path = match type_ref {
- TypeRef::Path(path) => path,
- &TypeRef::TypeParam(idx) => return Some(idx.into()),
- _ => return None,
- };
- if path.type_anchor().is_some() {
- return None;
- }
- if path.segments().len() > 1 {
- return None;
- }
- let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) {
- Some((it, None, _)) => it,
- _ => return None,
- };
- match resolution {
- TypeNs::GenericParam(param_id) => Some(param_id.into()),
- _ => None,
- }
- }
-
- #[inline]
- fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> {
- PathDiagnosticCallback {
- data: Either::Left(PathDiagnosticCallbackData(type_ref)),
- callback: |data, this, diag| {
- let type_ref = data.as_ref().left().unwrap().0;
- this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
- },
- }
- }
-
- #[inline]
- fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> {
- PathLoweringContext::new(
- self,
- Self::on_path_diagnostic_callback(path_id.type_ref()),
- &self.store[path_id],
- )
- }
-
- pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option<TypeNs>) {
- // Resolve the path (in type namespace)
- if let Some(type_ref) = path.type_anchor() {
- let (ty, res) = self.lower_ty_ext(type_ref);
- let mut ctx = self.at_path(path_id);
- return ctx.lower_ty_relative_path(ty, res, false);
- }
-
- let mut ctx = self.at_path(path_id);
- let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
- Some(it) => it,
- None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
- };
-
- if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
- // trait object type without dyn
- let bound = TypeBound::Path(path_id, TraitBoundModifier::None);
- let ty = self.lower_dyn_trait(&[bound]);
- return (ty, None);
- }
-
- ctx.lower_partly_resolved_path(resolution, false)
- }
-
- fn lower_trait_ref_from_path(
- &mut self,
- path_id: PathId,
- explicit_self_ty: Ty<'db>,
- ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> {
- let mut ctx = self.at_path(path_id);
- let resolved = match ctx.resolve_path_in_type_ns_fully()? {
- // FIXME(trait_alias): We need to handle trait alias here.
- TypeNs::TraitId(tr) => tr,
- _ => return None,
- };
- Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
- }
-
- fn lower_trait_ref(
- &mut self,
- trait_ref: &HirTraitRef,
- explicit_self_ty: Ty<'db>,
- ) -> Option<TraitRef<'db>> {
- self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
- }
-
- pub(crate) fn lower_where_predicate<'b>(
- &'b mut self,
- where_predicate: &'b WherePredicate,
- ignore_bindings: bool,
- generics: &Generics,
- predicate_filter: PredicateFilter,
- ) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
- match where_predicate {
- WherePredicate::ForLifetime { target, bound, .. }
- | WherePredicate::TypeBound { target, bound } => {
- if let PredicateFilter::SelfTrait = predicate_filter {
- let target_type = &self.store[*target];
- let self_type = 'is_self: {
- if let TypeRef::Path(path) = target_type
- && path.is_self_type()
- {
- break 'is_self true;
- }
- if let TypeRef::TypeParam(param) = target_type
- && generics[param.local_id()].is_trait_self()
- {
- break 'is_self true;
- }
- false
- };
- if !self_type {
- return Either::Left(Either::Left(iter::empty()));
- }
- }
- let self_ty = self.lower_ty(*target);
- Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
- }
- &WherePredicate::Lifetime { bound, target } => {
- Either::Right(iter::once(Clause(Predicate::new(
- self.interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
- self.lower_lifetime(bound),
- self.lower_lifetime(target),
- )),
- )),
- ))))
- }
- }
- .into_iter()
- }
-
- pub(crate) fn lower_type_bound<'b>(
- &'b mut self,
- bound: &'b TypeBound,
- self_ty: Ty<'db>,
- ignore_bindings: bool,
- ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
- let interner = self.interner;
- let mut assoc_bounds = None;
- let mut clause = None;
- match bound {
- &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
- // FIXME Don't silently drop the hrtb lifetimes here
- if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
- // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
- // sized-hierarchy correctly.
- let meta_sized = LangItem::MetaSized
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let pointee_sized = LangItem::PointeeSized
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) {
- // Ignore this bound
- } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) {
- // Regard this as `?Sized` bound
- ctx.ty_ctx().unsized_types.insert(self_ty);
- } else {
- if !ignore_bindings {
- assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
- }
- clause = Some(Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- )));
- }
- }
- }
- &TypeBound::Path(path, TraitBoundModifier::Maybe) => {
- let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate());
- // Don't lower associated type bindings as the only possible relaxed trait bound
- // `?Sized` has no of them.
- // If we got another trait here ignore the bound completely.
- let trait_id = self
- .lower_trait_ref_from_path(path, self_ty)
- .map(|(trait_ref, _)| trait_ref.def_id.0);
- if trait_id == sized_trait {
- self.unsized_types.insert(self_ty);
- }
- }
- &TypeBound::Lifetime(l) => {
- let lifetime = self.lower_lifetime(l);
- clause = Some(Clause(Predicate::new(
- self.interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate(
- self_ty, lifetime,
- )),
- )),
- )));
- }
- TypeBound::Use(_) | TypeBound::Error => {}
- }
- clause.into_iter().chain(assoc_bounds.into_iter().flatten())
- }
-
- fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
- let interner = self.interner;
- // FIXME: we should never create non-existential predicates in the first place
- // For now, use an error type so we don't run into dummy binder issues
- let self_ty = Ty::new_error(interner, ErrorGuaranteed);
- // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
- // order but should be in the same order for the same set but possibly different order of
- // bounds in the input.
- // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
- // These invariants are utilized by `TyExt::dyn_trait()` and chalk.
- let mut lifetime = None;
- let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
- let mut lowered_bounds: Vec<
- rustc_type_ir::Binder<DbInterner<'db>, ExistentialPredicate<DbInterner<'db>>>,
- > = Vec::new();
- for b in bounds {
- let db = ctx.db;
- ctx.lower_type_bound(b, self_ty, false).for_each(|b| {
- if let Some(bound) = b
- .kind()
- .map_bound(|c| match c {
- rustc_type_ir::ClauseKind::Trait(t) => {
- let id = t.def_id();
- let is_auto =
- db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
- if is_auto {
- Some(ExistentialPredicate::AutoTrait(t.def_id()))
- } else {
- Some(ExistentialPredicate::Trait(
- ExistentialTraitRef::new_from_args(
- interner,
- t.def_id(),
- GenericArgs::new_from_iter(
- interner,
- t.trait_ref.args.iter().skip(1),
- ),
- ),
- ))
- }
- }
- rustc_type_ir::ClauseKind::Projection(p) => {
- Some(ExistentialPredicate::Projection(
- ExistentialProjection::new_from_args(
- interner,
- p.def_id(),
- GenericArgs::new_from_iter(
- interner,
- p.projection_term.args.iter().skip(1),
- ),
- p.term,
- ),
- ))
- }
- rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => {
- lifetime = Some(outlives_predicate.1);
- None
- }
- rustc_type_ir::ClauseKind::RegionOutlives(_)
- | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
- | rustc_type_ir::ClauseKind::WellFormed(_)
- | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
- | rustc_type_ir::ClauseKind::HostEffect(_)
- | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
- })
- .transpose()
- {
- lowered_bounds.push(bound);
- }
- })
- }
-
- let mut multiple_regular_traits = false;
- let mut multiple_same_projection = false;
- lowered_bounds.sort_unstable_by(|lhs, rhs| {
- use std::cmp::Ordering;
- match ((*lhs).skip_binder(), (*rhs).skip_binder()) {
- (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => {
- multiple_regular_traits = true;
- // Order doesn't matter - we error
- Ordering::Equal
- }
- (
- ExistentialPredicate::AutoTrait(lhs_id),
- ExistentialPredicate::AutoTrait(rhs_id),
- ) => lhs_id.0.cmp(&rhs_id.0),
- (ExistentialPredicate::Trait(_), _) => Ordering::Less,
- (_, ExistentialPredicate::Trait(_)) => Ordering::Greater,
- (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less,
- (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater,
- (
- ExistentialPredicate::Projection(lhs),
- ExistentialPredicate::Projection(rhs),
- ) => {
- let lhs_id = match lhs.def_id {
- SolverDefId::TypeAliasId(id) => id,
- _ => unreachable!(),
- };
- let rhs_id = match rhs.def_id {
- SolverDefId::TypeAliasId(id) => id,
- _ => unreachable!(),
- };
- // We only compare the `associated_ty_id`s. We shouldn't have
- // multiple bounds for an associated type in the correct Rust code,
- // and if we do, we error out.
- if lhs_id == rhs_id {
- multiple_same_projection = true;
- }
- lhs_id.as_id().index().cmp(&rhs_id.as_id().index())
- }
- }
- });
-
- if multiple_regular_traits || multiple_same_projection {
- return None;
- }
-
- if !lowered_bounds.first().map_or(false, |b| {
- matches!(
- b.as_ref().skip_binder(),
- ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_)
- )
- }) {
- return None;
- }
-
- // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the
- // bounds. We shouldn't have repeated elements besides auto traits at this point.
- lowered_bounds.dedup();
-
- Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds))
- });
-
- if let Some(bounds) = bounds {
- let region = match lifetime {
- Some(it) => match it.kind() {
- rustc_type_ir::RegionKind::ReBound(db, var) => Region::new_bound(
- self.interner,
- db.shifted_out_to_binder(DebruijnIndex::from_u32(2)),
- var,
- ),
- _ => it,
- },
- None => Region::new_static(self.interner),
- };
- Ty::new_dynamic(self.interner, bounds, region)
- } else {
- // FIXME: report error
- // (additional non-auto traits, associated type rebound, or no resolved trait)
- Ty::new_error(self.interner, ErrorGuaranteed)
- }
- }
-
- fn lower_impl_trait(
- &mut self,
- def_id: SolverDefId,
- bounds: &[TypeBound],
- krate: Crate,
- ) -> ImplTrait<'db> {
- let interner = self.interner;
- cov_mark::hit!(lower_rpit);
- let args = GenericArgs::identity_for_item(interner, def_id);
- let self_ty = Ty::new_alias(
- self.interner,
- rustc_type_ir::AliasTyKind::Opaque,
- AliasTy::new_from_args(interner, def_id, args),
- );
- let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
- let mut predicates = Vec::new();
- for b in bounds {
- predicates.extend(ctx.lower_type_bound(b, self_ty, false));
- }
-
- if !ctx.unsized_types.contains(&self_ty) {
- let sized_trait = LangItem::Sized.resolve_trait(self.db, krate);
- let sized_clause = sized_trait.map(|trait_id| {
- let trait_ref = TraitRef::new_from_args(
- interner,
- trait_id.into(),
- GenericArgs::new_from_iter(interner, [self_ty.into()]),
- );
- Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- ))
- });
- predicates.extend(sized_clause);
- }
- predicates.shrink_to_fit();
- predicates
- });
- ImplTrait { predicates }
- }
-
- pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
- match self.resolver.resolve_lifetime(&self.store[lifetime]) {
- Some(resolution) => match resolution {
- LifetimeNs::Static => Region::new_static(self.interner),
- LifetimeNs::LifetimeParam(id) => {
- let idx = match self.generics().lifetime_idx(id) {
- None => return Region::error(self.interner),
- Some(idx) => idx,
- };
- self.region_param(id, idx as u32)
- }
- },
- None => Region::error(self.interner),
- }
- }
-}
-
-pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
- match m {
- hir_def::type_ref::Mutability::Shared => Mutability::Not,
- hir_def::type_ref::Mutability::Mut => Mutability::Mut,
- }
-}
-
-fn unknown_const(_ty: Ty<'_>) -> Const<'_> {
- Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed))
-}
-
-pub(crate) fn impl_trait_query<'db>(
- db: &'db dyn HirDatabase,
- impl_id: ImplId,
-) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
- db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
-}
-
-pub(crate) fn impl_trait_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- impl_id: ImplId,
-) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> {
- let impl_data = db.impl_signature(impl_id);
- let resolver = impl_id.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &impl_data.store,
- impl_id.into(),
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
- );
- let self_ty = db.impl_self_ty(impl_id).skip_binder();
- let target_trait = impl_data.target_trait.as_ref()?;
- let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
- Some((trait_ref, create_diagnostics(ctx.diagnostics)))
-}
-
-pub(crate) fn return_type_impl_traits<'db>(
- db: &'db dyn HirDatabase,
- def: hir_def::FunctionId,
-) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
- // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
- let data = db.function_signature(def);
- let resolver = def.resolver(db);
- let mut ctx_ret =
- TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
- if let Some(ret_type) = data.ret_type {
- let _ret = ctx_ret.lower_ty(ret_type);
- }
- let return_type_impl_traits =
- ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
- if return_type_impl_traits.impl_traits.is_empty() {
- None
- } else {
- Some(Arc::new(EarlyBinder::bind(return_type_impl_traits)))
- }
-}
-
-pub(crate) fn type_alias_impl_traits<'db>(
- db: &'db dyn HirDatabase,
- def: hir_def::TypeAliasId,
-) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
- let data = db.type_alias_signature(def);
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
- if let Some(type_ref) = data.ty {
- let _ty = ctx.lower_ty(type_ref);
- }
- let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
- if type_alias_impl_traits.impl_traits.is_empty() {
- None
- } else {
- Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits)))
- }
-}
-
-/// Build the declared type of an item. This depends on the namespace; e.g. for
-/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
-/// the constructor function `(usize) -> Foo` which lives in the values
-/// namespace.
-pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
- let interner = DbInterner::new_with(db, None, None);
- match def {
- TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)),
- TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt(
- interner,
- it,
- GenericArgs::identity_for_item(interner, it.into()),
- )),
- TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
- }
-}
-
-/// Build the declared type of a function. This should not need to look at the
-/// function body.
-fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> {
- let interner = DbInterner::new_with(db, None, None);
- EarlyBinder::bind(Ty::new_fn_def(
- interner,
- CallableDefId::FunctionId(def).into(),
- GenericArgs::identity_for_item(interner, def.into()),
- ))
-}
-
-/// Build the declared type of a const.
-fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
- let resolver = def.resolver(db);
- let data = db.const_signature(def);
- let parent = def.loc(db).container;
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::AnonymousReportError,
- );
- ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent));
- EarlyBinder::bind(ctx.lower_ty(data.type_ref))
-}
-
-/// Build the declared type of a static.
-fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
- let resolver = def.resolver(db);
- let module = resolver.module();
- let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
- let data = db.static_signature(def);
- let parent = def.loc(db).container;
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::AnonymousReportError,
- );
- ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner)));
- EarlyBinder::bind(ctx.lower_ty(data.type_ref))
-}
-
-/// Build the type of a tuple struct constructor.
-fn type_for_struct_constructor<'db>(
- db: &'db dyn HirDatabase,
- def: StructId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
- let struct_data = def.fields(db);
- match struct_data.shape {
- FieldsShape::Record => None,
- FieldsShape::Unit => Some(type_for_adt(db, def.into())),
- FieldsShape::Tuple => {
- let interner = DbInterner::new_with(db, None, None);
- Some(EarlyBinder::bind(Ty::new_fn_def(
- interner,
- CallableDefId::StructId(def).into(),
- GenericArgs::identity_for_item(interner, def.into()),
- )))
- }
- }
-}
-
-/// Build the type of a tuple enum variant constructor.
-fn type_for_enum_variant_constructor<'db>(
- db: &'db dyn HirDatabase,
- def: EnumVariantId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
- let struct_data = def.fields(db);
- match struct_data.shape {
- FieldsShape::Record => None,
- FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())),
- FieldsShape::Tuple => {
- let interner = DbInterner::new_with(db, None, None);
- Some(EarlyBinder::bind(Ty::new_fn_def(
- interner,
- CallableDefId::EnumVariantId(def).into(),
- GenericArgs::identity_for_item(interner, def.loc(db).parent.into()),
- )))
- }
- }
-}
-
-pub(crate) fn value_ty_query<'db>(
- db: &'db dyn HirDatabase,
- def: ValueTyDefId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
- match def {
- ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
- ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
- ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
- ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
- ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
- ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
- }
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- t: TypeAliasId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
- let type_alias_data = db.type_alias_signature(t);
- let mut diags = None;
- let resolver = t.resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
- EarlyBinder::bind(Ty::new_foreign(interner, t.into()))
- } else {
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &type_alias_data.store,
- t.into(),
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
- let res = EarlyBinder::bind(
- type_alias_data
- .ty
- .map(|type_ref| ctx.lower_ty(type_ref))
- .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)),
- );
- diags = create_diagnostics(ctx.diagnostics);
- res
- };
- (inner, diags)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>(
- db: &'db dyn HirDatabase,
- _adt: TypeAliasId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
- (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
-}
-
-pub(crate) fn impl_self_ty_query<'db>(
- db: &'db dyn HirDatabase,
- impl_id: ImplId,
-) -> EarlyBinder<'db, Ty<'db>> {
- db.impl_self_ty_with_diagnostics(impl_id).0
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- impl_id: ImplId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
- let resolver = impl_id.resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-
- let impl_data = db.impl_signature(impl_id);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &impl_data.store,
- impl_id.into(),
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
- );
- let ty = ctx.lower_ty(impl_data.self_ty);
- assert!(!ty.has_escaping_bound_vars());
- (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics))
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
- db: &dyn HirDatabase,
- _impl_id: ImplId,
-) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) {
- (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
-}
-
-pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
- db.const_param_ty_with_diagnostics(def).0
-}
-
-// returns None if def is a type arg
-pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- def: ConstParamId,
-) -> (Ty<'db>, Diagnostics) {
- let (parent_data, store) = db.generic_params_and_store(def.parent());
- let data = &parent_data[def.local_id()];
- let resolver = def.parent().resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &store,
- def.parent(),
- LifetimeElisionKind::AnonymousReportError,
- );
- let ty = match data {
- TypeOrConstParamData::TypeParamData(_) => {
- never!();
- Ty::new_error(interner, ErrorGuaranteed)
- }
- TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
- };
- (ty, create_diagnostics(ctx.diagnostics))
-}
-
-pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
- db: &'db dyn HirDatabase,
- _: crate::db::HirDatabaseData,
- def: ConstParamId,
-) -> (Ty<'db>, Diagnostics) {
- let resolver = def.parent().resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- (Ty::new_error(interner, ErrorGuaranteed), None)
-}
-
-pub(crate) fn field_types_query<'db>(
- db: &'db dyn HirDatabase,
- variant_id: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
- db.field_types_with_diagnostics(variant_id).0
-}
-
-/// Build the type of all specific fields of a struct or enum variant.
-pub(crate) fn field_types_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- variant_id: VariantId,
-) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) {
- let var_data = variant_id.fields(db);
- let fields = var_data.fields();
- if fields.is_empty() {
- return (Arc::new(ArenaMap::default()), None);
- }
-
- let (resolver, def): (_, GenericDefId) = match variant_id {
- VariantId::StructId(it) => (it.resolver(db), it.into()),
- VariantId::UnionId(it) => (it.resolver(db), it.into()),
- VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
- };
- let mut res = ArenaMap::default();
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &var_data.store,
- def,
- LifetimeElisionKind::AnonymousReportError,
- );
- for (field_id, field_data) in var_data.fields().iter() {
- res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref)));
- }
- (Arc::new(res), create_diagnostics(ctx.diagnostics))
-}
-
-/// This query exists only to be used when resolving short-hand associated types
-/// like `T::Item`.
-///
-/// See the analogous query in rustc and its comment:
-/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
-/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
-/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
-/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
-#[tracing::instrument(skip(db), ret)]
-pub(crate) fn generic_predicates_for_param_query<'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
- param_id: TypeOrConstParamId,
- assoc_name: Option<Name>,
-) -> GenericPredicates<'db> {
- let generics = generics(db, def);
- let interner = DbInterner::new_with(db, None, None);
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generics.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- );
-
- // we have to filter out all other predicates *first*, before attempting to lower them
- let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
- WherePredicate::ForLifetime { target, bound, .. }
- | WherePredicate::TypeBound { target, bound, .. } => {
- let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
- if invalid_target {
- // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
- // sized-hierarchy correctly.
- // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
- // `ctx.unsized_types`
- let lower = || -> bool {
- match bound {
- TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
- TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
- let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
- return false;
- };
- let Some(pointee_sized) =
- LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
- else {
- return false;
- };
- // Lower the path directly with `Resolver` instead of PathLoweringContext`
- // to prevent diagnostics duplications.
- ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
- |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
- )
- }
- _ => false,
- }
- }();
- if lower {
- ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
- .for_each(drop);
- }
- return false;
- }
-
- match bound {
- &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
- // Only lower the bound if the trait could possibly define the associated
- // type we're looking for.
- let path = &ctx.store[path];
-
- let Some(assoc_name) = &assoc_name else { return true };
- let Some(TypeNs::TraitId(tr)) =
- resolver.resolve_path_in_type_ns_fully(db, path)
- else {
- return false;
- };
-
- rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
- tr.0.trait_items(db).items.iter().any(|(name, item)| {
- matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
- })
- })
- }
- TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
- }
- }
- WherePredicate::Lifetime { .. } => false,
- };
- let mut predicates = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- if predicate(pred, &mut ctx) {
- predicates.extend(ctx.lower_where_predicate(
- pred,
- true,
- maybe_parent_generics,
- PredicateFilter::All,
- ));
- }
- }
- }
-
- let args = GenericArgs::identity_for_item(interner, def.into());
- if !args.is_empty() {
- let explicitly_unsized_tys = ctx.unsized_types;
- if let Some(implicitly_sized_predicates) =
- implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver)
- {
- predicates.extend(implicitly_sized_predicates);
- };
- }
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
-}
-
-pub(crate) fn generic_predicates_for_param_cycle_result(
- _db: &dyn HirDatabase,
- _def: GenericDefId,
- _param_id: TypeOrConstParamId,
- _assoc_name: Option<Name>,
-) -> GenericPredicates<'_> {
- GenericPredicates(None)
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
-
-impl<'db> GenericPredicates<'db> {
- #[inline]
- pub fn instantiate(
- &self,
- interner: DbInterner<'db>,
- args: GenericArgs<'db>,
- ) -> Option<impl Iterator<Item = Clause<'db>>> {
- self.0
- .as_ref()
- .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
- }
-
- #[inline]
- pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> {
- self.0.as_ref().map(|it| it.iter().copied())
- }
-}
-
-impl<'db> ops::Deref for GenericPredicates<'db> {
- type Target = [Clause<'db>];
-
- fn deref(&self) -> &Self::Target {
- self.0.as_deref().unwrap_or(&[])
- }
-}
-
-pub(crate) fn trait_environment_for_body_query(
- db: &dyn HirDatabase,
- def: DefWithBodyId,
-) -> Arc<TraitEnvironment<'_>> {
- let Some(def) = def.as_generic_def_id(db) else {
- let krate = def.module(db).krate();
- return TraitEnvironment::empty(krate);
- };
- db.trait_environment(def)
-}
-
-pub(crate) fn trait_environment_query<'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
-) -> Arc<TraitEnvironment<'db>> {
- let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return TraitEnvironment::empty(def.krate(db));
- }
-
- let interner = DbInterner::new_with(db, Some(def.krate(db)), None);
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generics.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- );
- let mut traits_in_scope = Vec::new();
- let mut clauses = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
- if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
- traits_in_scope.push((tr.self_ty(), tr.def_id().0));
- }
- clauses.push(pred);
- }
- }
- }
-
- if let Some(trait_id) = def.assoc_trait_container(db) {
- // add `Self: Trait<T1, T2, ...>` to the environment in trait
- // function default implementations (and speculative code
- // inside consts or type aliases)
- cov_mark::hit!(trait_self_implements_self);
- let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
- let clause = Clause(Predicate::new(
- ctx.interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
- TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
- ))),
- ));
- clauses.push(clause);
- }
-
- let explicitly_unsized_tys = ctx.unsized_types;
-
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
- if let Some(sized_trait) = sized_trait {
- let (mut generics, mut def_id) =
- (crate::next_solver::generics::generics(db, def.into()), def);
- loop {
- let self_idx = trait_self_param_idx(db, def_id);
- for (idx, p) in generics.own_params.iter().enumerate() {
- if let Some(self_idx) = self_idx
- && p.index() as usize == self_idx
- {
- continue;
- }
- let GenericParamId::TypeParamId(param_id) = p.id else {
- continue;
- };
- let idx = idx as u32 + generics.parent_count as u32;
- let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone());
- if explicitly_unsized_tys.contains(¶m_ty) {
- continue;
- }
- let trait_ref = TraitRef::new_from_args(
- ctx.interner,
- sized_trait.into(),
- GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
- );
- let clause = Clause(Predicate::new(
- ctx.interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- ));
- clauses.push(clause);
- }
-
- if let Some(g) = generics.parent {
- generics = crate::next_solver::generics::generics(db, g.into());
- def_id = g;
- } else {
- break;
- }
- }
- }
-
- let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
- let clauses = Clauses::new_from_iter(ctx.interner, clauses);
- let env = ParamEnv { clauses };
-
- TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
-}
-
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum PredicateFilter {
- SelfTrait,
- All,
-}
-
-/// Resolve the where clause(s) of an item with generics.
-#[tracing::instrument(skip(db))]
-pub(crate) fn generic_predicates_query<'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
-) -> GenericPredicates<'db> {
- generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0
-}
-
-pub(crate) fn generic_predicates_without_parent_query<'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
-) -> GenericPredicates<'db> {
- generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// except the ones inherited from the parent
-pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
-) -> (GenericPredicates<'db>, Diagnostics) {
- generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def)
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// with a given filter
-#[tracing::instrument(skip(db, filter), ret)]
-pub(crate) fn generic_predicates_filtered_by<'db, F>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
- predicate_filter: PredicateFilter,
- filter: F,
-) -> (GenericPredicates<'db>, Diagnostics)
-where
- F: Fn(GenericDefId) -> bool,
-{
- let generics = generics(db, def);
- let resolver = def.resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generics.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- );
-
- let mut predicates = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- tracing::debug!(?pred);
- if filter(maybe_parent_generics.def()) {
- // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
- // If we use the parent generics
- predicates.extend(ctx.lower_where_predicate(
- pred,
- false,
- maybe_parent_generics,
- predicate_filter,
- ));
- }
- }
- }
-
- let explicitly_unsized_tys = ctx.unsized_types;
-
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
- if let Some(sized_trait) = sized_trait {
- let (mut generics, mut def_id) =
- (crate::next_solver::generics::generics(db, def.into()), def);
- loop {
- if filter(def_id) {
- let self_idx = trait_self_param_idx(db, def_id);
- for (idx, p) in generics.own_params.iter().enumerate() {
- if let Some(self_idx) = self_idx
- && p.index() as usize == self_idx
- {
- continue;
- }
- let GenericParamId::TypeParamId(param_id) = p.id else {
- continue;
- };
- let idx = idx as u32 + generics.parent_count as u32;
- let param_ty = Ty::new_param(interner, param_id, idx, p.name.clone());
- if explicitly_unsized_tys.contains(¶m_ty) {
- continue;
- }
- let trait_ref = TraitRef::new_from_args(
- interner,
- sized_trait.into(),
- GenericArgs::new_from_iter(interner, [param_ty.into()]),
- );
- let clause = Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- ));
- predicates.push(clause);
- }
- }
-
- if let Some(g) = generics.parent {
- generics = crate::next_solver::generics::generics(db, g.into());
- def_id = g;
- } else {
- break;
- }
- }
- }
-
- // FIXME: rustc gathers more predicates by recursing through resulting trait predicates.
- // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715
-
- (
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
- create_diagnostics(ctx.diagnostics),
- )
-}
-
-/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
-/// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'a, 'subst, 'db>(
- db: &'db dyn HirDatabase,
- def: GenericDefId,
- explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
- args: &'subst GenericArgs<'db>,
- resolver: &Resolver<'db>,
-) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?;
-
- let trait_self_idx = trait_self_param_idx(db, def);
-
- Some(
- args.iter()
- .enumerate()
- .filter_map(
- move |(idx, generic_arg)| {
- if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
- },
- )
- .filter_map(|generic_arg| generic_arg.as_type())
- .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
- .map(move |self_ty| {
- let trait_ref = TraitRef::new_from_args(
- interner,
- sized_trait.into(),
- GenericArgs::new_from_iter(interner, [self_ty.into()]),
- );
- Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- ))
- }),
- )
-}
-
-pub(crate) fn make_binders<'db, T: rustc_type_ir::TypeVisitable<DbInterner<'db>>>(
- interner: DbInterner<'db>,
- generics: &Generics,
- value: T,
-) -> Binder<'db, T> {
- Binder::bind_with_vars(
- value,
- BoundVarKinds::new_from_iter(
- interner,
- generics.iter_id().map(|x| match x {
- hir_def::GenericParamId::ConstParamId(_) => BoundVarKind::Const,
- hir_def::GenericParamId::TypeParamId(_) => BoundVarKind::Ty(BoundTyKind::Anon),
- hir_def::GenericParamId::LifetimeParamId(_) => {
- BoundVarKind::Region(BoundRegionKind::Anon)
- }
- }),
- ),
- )
-}
-
-/// Checks if the provided generic arg matches its expected kind, then lower them via
-/// provided closures. Use unknown if there was kind mismatch.
-///
-pub(crate) fn lower_generic_arg<'a, 'db, T>(
- db: &'db dyn HirDatabase,
- kind_id: GenericParamId,
- arg: &'a GenericArg,
- this: &mut T,
- store: &ExpressionStore,
- for_type: impl FnOnce(&mut T, TypeRefId) -> Ty<'db> + 'a,
- for_const: impl FnOnce(&mut T, &ConstRef, Ty<'db>) -> Const<'db> + 'a,
- for_const_ty_path_fallback: impl FnOnce(&mut T, &Path, Ty<'db>) -> Const<'db> + 'a,
- for_lifetime: impl FnOnce(&mut T, &LifetimeRefId) -> Region<'db> + 'a,
-) -> crate::next_solver::GenericArg<'db> {
- let interner = DbInterner::new_with(db, None, None);
- let kind = match kind_id {
- GenericParamId::TypeParamId(_) => ParamKind::Type,
- GenericParamId::ConstParamId(id) => {
- let ty = db.const_param_ty(id);
- ParamKind::Const(ty)
- }
- GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
- };
- match (arg, kind) {
- (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).into(),
- (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
- for_const(this, c, c_ty.to_nextsolver(interner)).into()
- }
- (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
- for_lifetime(this, lifetime_ref).into()
- }
- (GenericArg::Const(_), ParamKind::Type) => Ty::new_error(interner, ErrorGuaranteed).into(),
- (GenericArg::Lifetime(_), ParamKind::Type) => {
- Ty::new_error(interner, ErrorGuaranteed).into()
- }
- (GenericArg::Type(t), ParamKind::Const(c_ty)) => match &store[*t] {
- TypeRef::Path(p) => {
- for_const_ty_path_fallback(this, p, c_ty.to_nextsolver(interner)).into()
- }
- _ => unknown_const_as_generic(c_ty.to_nextsolver(interner)),
- },
- (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => {
- unknown_const(c_ty.to_nextsolver(interner)).into()
- }
- (GenericArg::Type(_), ParamKind::Lifetime) => Region::error(interner).into(),
- (GenericArg::Const(_), ParamKind::Lifetime) => Region::error(interner).into(),
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericDefaults<'db>(
- Option<Arc<[Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>]>>,
-);
-
-impl<'db> GenericDefaults<'db> {
- #[inline]
- pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>> {
- self.0.as_ref()?[idx]
- }
-}
-
-pub(crate) fn generic_defaults_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
-) -> GenericDefaults<'_> {
- db.generic_defaults_ns_with_diagnostics(def).0
-}
-
-/// Resolve the default type params from generics.
-///
-/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
-pub(crate) fn generic_defaults_with_diagnostics_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
-) -> (GenericDefaults<'_>, Diagnostics) {
- let generic_params = generics(db, def);
- if generic_params.is_empty() {
- return (GenericDefaults(None), None);
- }
- let resolver = def.resolver(db);
-
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- generic_params.store(),
- def,
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed);
- let mut idx = 0;
- let mut has_any_default = false;
- let mut defaults = generic_params
- .iter_parents_with_store()
- .map(|((id, p), store)| {
- ctx.store = store;
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
- has_any_default |= has_default;
- idx += 1;
- result
- })
- .collect::<Vec<_>>();
- ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
- defaults.extend(generic_params.iter_self().map(|(id, p)| {
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
- has_any_default |= has_default;
- idx += 1;
- result
- }));
- let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
- let defaults = if has_any_default {
- GenericDefaults(Some(Arc::from_iter(defaults)))
- } else {
- GenericDefaults(None)
- };
- return (defaults, diagnostics);
-
- fn handle_generic_param<'db>(
- ctx: &mut TyLoweringContext<'db, '_>,
- idx: usize,
- id: GenericParamId,
- p: GenericParamDataRef<'_>,
- generic_params: &Generics,
- ) -> (Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>, bool) {
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden.
- ctx.disallow_params_after(idx as u32);
- match p {
- GenericParamDataRef::TypeParamData(p) => {
- let ty = p.default.map(|ty| ctx.lower_ty(ty));
- (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some())
- }
- GenericParamDataRef::ConstParamData(p) => {
- let GenericParamId::ConstParamId(id) = id else {
- unreachable!("Unexpected lifetime or type argument")
- };
-
- let mut val = p.default.map(|c| {
- let param_ty = ctx.lower_ty(p.ty);
- let c = ctx.lower_const(c, param_ty);
- c.into()
- });
- (val.map(EarlyBinder::bind), p.default.is_some())
- }
- GenericParamDataRef::LifetimeParamData(_) => (None, false),
- }
- }
-}
-
-pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
- _db: &dyn HirDatabase,
- _def: GenericDefId,
-) -> (GenericDefaults<'_>, Diagnostics) {
- (GenericDefaults(None), None)
-}
-
-/// Build the signature of a callable item (function, struct or enum variant).
-pub(crate) fn callable_item_signature_query<'db>(
- db: &'db dyn HirDatabase,
- def: CallableDefId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
- match def {
- CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
- CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
- CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
- }
-}
-
-fn fn_sig_for_fn<'db>(
- db: &'db dyn HirDatabase,
- def: FunctionId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
- let data = db.function_signature(def);
- let resolver = def.resolver(db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let mut ctx_params = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::for_fn_params(&data),
- );
- let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
-
- let ret = match data.ret_type {
- Some(ret_type) => {
- let mut ctx_ret = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::for_fn_ret(interner),
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
- ctx_ret.lower_ty(ret_type)
- }
- None => Ty::new_tup(interner, &[]),
- };
-
- let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret)));
- // If/when we track late bound vars, we need to switch this to not be `dummy`
- EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig {
- abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
- c_variadic: data.is_varargs(),
- safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
- inputs_and_output,
- }))
-}
-
-fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> {
- let interner = DbInterner::new_with(db, None, None);
- let args = GenericArgs::identity_for_item(interner, adt.into());
- let ty = Ty::new_adt(interner, adt, args);
- EarlyBinder::bind(ty)
-}
-
-fn fn_sig_for_struct_constructor<'db>(
- db: &'db dyn HirDatabase,
- def: StructId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
- let field_tys = db.field_types_ns(def.into());
- let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
- let ret = type_for_adt(db, def.into()).skip_binder();
-
- let inputs_and_output =
- Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
- EarlyBinder::bind(Binder::dummy(FnSig {
- abi: FnAbi::RustCall,
- c_variadic: false,
- safety: Safety::Safe,
- inputs_and_output,
- }))
-}
-
-fn fn_sig_for_enum_variant_constructor<'db>(
- db: &'db dyn HirDatabase,
- def: EnumVariantId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
- let field_tys = db.field_types_ns(def.into());
- let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
- let parent = def.lookup(db).parent;
- let ret = type_for_adt(db, parent.into()).skip_binder();
-
- let inputs_and_output =
- Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
- EarlyBinder::bind(Binder::dummy(FnSig {
- abi: FnAbi::RustCall,
- c_variadic: false,
- safety: Safety::Safe,
- inputs_and_output,
- }))
-}
-
-// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way
-pub(crate) fn associated_ty_item_bounds<'db>(
- db: &'db dyn HirDatabase,
- type_alias: TypeAliasId,
-) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
- let trait_ = match type_alias.lookup(db).container {
- ItemContainerId::TraitId(t) => t,
- _ => panic!("associated type not in trait"),
- };
-
- let type_alias_data = db.type_alias_signature(type_alias);
- let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
- let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &type_alias_data.store,
- type_alias.into(),
- LifetimeElisionKind::AnonymousReportError,
- );
- // FIXME: we should never create non-existential predicates in the first place
- // For now, use an error type so we don't run into dummy binder issues
- let self_ty = Ty::new_error(interner, ErrorGuaranteed);
-
- let mut bounds = Vec::new();
- for bound in &type_alias_data.bounds {
- ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
- if let Some(bound) = pred
- .kind()
- .map_bound(|c| match c {
- rustc_type_ir::ClauseKind::Trait(t) => {
- let id = t.def_id();
- let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
- if is_auto {
- Some(ExistentialPredicate::AutoTrait(t.def_id()))
- } else {
- Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
- interner,
- t.def_id(),
- GenericArgs::new_from_iter(
- interner,
- t.trait_ref.args.iter().skip(1),
- ),
- )))
- }
- }
- rustc_type_ir::ClauseKind::Projection(p) => Some(
- ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
- interner,
- p.def_id(),
- GenericArgs::new_from_iter(
- interner,
- p.projection_term.args.iter().skip(1),
- ),
- p.term,
- )),
- ),
- rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => None,
- rustc_type_ir::ClauseKind::RegionOutlives(_)
- | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
- | rustc_type_ir::ClauseKind::WellFormed(_)
- | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
- | rustc_type_ir::ClauseKind::HostEffect(_)
- | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
- })
- .transpose()
- {
- bounds.push(bound);
- }
- });
- }
-
- if !ctx.unsized_types.contains(&self_ty) {
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
- let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
- interner,
- trait_.into(),
- [] as [crate::next_solver::GenericArg<'_>; 0],
- )));
- bounds.push(sized_clause);
- bounds.shrink_to_fit();
- }
-
- EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
-}
-
-pub(crate) fn associated_type_by_name_including_super_traits<'db>(
- db: &'db dyn HirDatabase,
- trait_ref: TraitRef<'db>,
- name: &Name,
-) -> Option<(TraitRef<'db>, TypeAliasId)> {
- let interner = DbInterner::new_with(db, None, None);
- rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
- let trait_id = t.as_ref().skip_binder().def_id.0;
- let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
- Some((t.skip_binder(), assoc_type))
- })
-}
-
-pub fn associated_type_shorthand_candidates(
- db: &dyn HirDatabase,
- def: GenericDefId,
- res: TypeNs,
- mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
-) -> Option<TypeAliasId> {
- let interner = DbInterner::new_with(db, None, None);
- named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
- cb(name, id).then_some(id)
- })
-}
-
-#[tracing::instrument(skip(interner, check_alias))]
-fn named_associated_type_shorthand_candidates<'db, R>(
- interner: DbInterner<'db>,
- // If the type parameter is defined in an impl and we're in a method, there
- // might be additional where clauses to consider
- def: GenericDefId,
- res: TypeNs,
- assoc_name: Option<Name>,
- mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
-) -> Option<R> {
- let db = interner.db;
- let mut search = |t: TraitRef<'db>| -> Option<R> {
- let trait_id = t.def_id.0;
- let mut checked_traits = FxHashSet::default();
- let mut check_trait = |trait_ref: TraitRef<'db>| {
- let trait_id = trait_ref.def_id.0;
- let name = &db.trait_signature(trait_id).name;
- tracing::debug!(?trait_id, ?name);
- if !checked_traits.insert(trait_id) {
- return None;
- }
- let data = trait_id.trait_items(db);
-
- tracing::debug!(?data.items);
- for (name, assoc_id) in &data.items {
- if let &AssocItemId::TypeAliasId(alias) = assoc_id
- && let Some(ty) = check_alias(name, trait_ref, alias)
- {
- return Some(ty);
- }
- }
- None
- };
- let mut stack: SmallVec<[_; 4]> = smallvec![t];
- while let Some(trait_ref) = stack.pop() {
- if let Some(alias) = check_trait(trait_ref) {
- return Some(alias);
- }
- for pred in generic_predicates_filtered_by(
- db,
- GenericDefId::TraitId(trait_ref.def_id.0),
- PredicateFilter::SelfTrait,
- // We are likely in the midst of lowering generic predicates of `def`.
- // So, if we allow `pred == def` we might fall into an infinite recursion.
- // Actually, we have already checked for the case `pred == def` above as we started
- // with a stack including `trait_id`
- |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
- )
- .0
- .deref()
- {
- tracing::debug!(?pred);
- let sup_trait_ref = match pred.kind().skip_binder() {
- rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
- _ => continue,
- };
- let sup_trait_ref =
- EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
- stack.push(sup_trait_ref);
- }
- tracing::debug!(?stack);
- }
-
- None
- };
-
- match res {
- TypeNs::SelfType(impl_id) => {
- let trait_ref = db.impl_trait(impl_id)?;
-
- // FIXME(next-solver): same method in `lower` checks for impl or not
- // Is that needed here?
-
- // we're _in_ the impl -- the binders get added back later. Correct,
- // but it would be nice to make this more explicit
- search(trait_ref.skip_binder())
- }
- TypeNs::GenericParam(param_id) => {
- // Handle `Self::Type` referring to own associated type in trait definitions
- // This *must* be done first to avoid cycles with
- // `generic_predicates_for_param`, but not sure that it's sufficient,
- if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let trait_name = &db.trait_signature(trait_id).name;
- tracing::debug!(?trait_name);
- let trait_generics = generics(db, trait_id.into());
- tracing::debug!(?trait_generics);
- if trait_generics[param_id.local_id()].is_trait_self() {
- let args = crate::next_solver::GenericArgs::identity_for_item(
- interner,
- trait_id.into(),
- );
- let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
- tracing::debug!(?args, ?trait_ref);
- return search(trait_ref);
- }
- }
-
- let predicates =
- db.generic_predicates_for_param_ns(def, param_id.into(), assoc_name.clone());
- predicates
- .iter()
- .find_map(|pred| match (*pred).kind().skip_binder() {
- rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
- _ => None,
- })
- .and_then(|trait_predicate| {
- let trait_ref = trait_predicate.trait_ref;
- assert!(
- !trait_ref.has_escaping_bound_vars(),
- "FIXME unexpected higher-ranked trait bound"
- );
- search(trait_ref)
- })
- }
- _ => None,
- }
-}
diff --git a/crates/hir-ty/src/lower_nextsolver/path.rs b/crates/hir-ty/src/lower_nextsolver/path.rs
deleted file mode 100644
index ef2c392..0000000
--- a/crates/hir-ty/src/lower_nextsolver/path.rs
+++ /dev/null
@@ -1,1354 +0,0 @@
-//! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
-
-use std::ops::Deref;
-
-use either::Either;
-use hir_def::{
- AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
- builtin_type::BuiltinType,
- expr_store::{
- ExpressionStore, HygieneId,
- path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
- },
- hir::generics::{
- GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
- },
- resolver::{ResolveValueResult, TypeNs, ValueNs},
- signatures::TraitFlags,
- type_ref::{TypeRef, TypeRefId},
-};
-use hir_expand::name::Name;
-use intern::sym;
-use rustc_hash::FxHashSet;
-use rustc_type_ir::{
- AliasTerm, AliasTy, AliasTyKind, TypeVisitableExt,
- inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
-};
-use smallvec::{SmallVec, smallvec};
-use stdx::never;
-
-use crate::{
- GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
- PathLoweringDiagnostic, TyDefId, ValueTyDefId,
- consteval::{unknown_const, unknown_const_as_generic},
- db::HirDatabase,
- generics::{Generics, generics},
- lower::PathDiagnosticCallbackData,
- lower_nextsolver::{
- LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by,
- named_associated_type_shorthand_candidates,
- },
- next_solver::{
- AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate,
- Region, SolverDefId, TraitRef, Ty,
- mapping::{ChalkToNextSolver, convert_binder_to_early_binder},
- },
- primitive,
-};
-
-use super::{
- ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
- const_param_ty_query, ty_query,
-};
-
-type CallbackData<'a, 'db> = Either<
- PathDiagnosticCallbackData,
- crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>,
->;
-
-// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box<dyn FnMut()>`
-// because of the allocation, so we create a lifetime-less callback, tailored for our needs.
-pub(crate) struct PathDiagnosticCallback<'a, 'db> {
- pub(crate) data: CallbackData<'a, 'db>,
- pub(crate) callback:
- fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
-}
-
-pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
- ctx: &'a mut TyLoweringContext<'db, 'b>,
- on_diagnostic: PathDiagnosticCallback<'a, 'db>,
- path: &'a Path,
- segments: PathSegments<'a>,
- current_segment_idx: usize,
- /// Contains the previous segment if `current_segment_idx == segments.len()`
- current_or_prev_segment: PathSegment<'a>,
-}
-
-impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
- #[inline]
- pub(crate) fn new(
- ctx: &'a mut TyLoweringContext<'db, 'b>,
- on_diagnostic: PathDiagnosticCallback<'a, 'db>,
- path: &'a Path,
- ) -> Self {
- let segments = path.segments();
- let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
- Self {
- ctx,
- on_diagnostic,
- path,
- segments,
- current_segment_idx: 0,
- current_or_prev_segment: first_segment,
- }
- }
-
- #[inline]
- #[cold]
- fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
- (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag);
- }
-
- #[inline]
- pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> {
- self.ctx
- }
-
- #[inline]
- fn current_segment_u32(&self) -> u32 {
- self.current_segment_idx as u32
- }
-
- #[inline]
- fn skip_resolved_segment(&mut self) {
- if !matches!(self.path, Path::LangItem(..)) {
- // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it
- // point at -1, but I don't feel this is clearer.
- self.current_segment_idx += 1;
- }
- self.update_current_segment();
- }
-
- #[inline]
- fn update_current_segment(&mut self) {
- self.current_or_prev_segment =
- self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment);
- }
-
- #[inline]
- pub(crate) fn ignore_last_segment(&mut self) {
- self.segments = self.segments.strip_last();
- }
-
- #[inline]
- pub(crate) fn set_current_segment(&mut self, segment: usize) {
- self.current_segment_idx = segment;
- self.current_or_prev_segment = self
- .segments
- .get(segment)
- .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
- }
-
- #[inline]
- fn with_lifetime_elision<T>(
- &mut self,
- lifetime_elision: LifetimeElisionKind<'db>,
- f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
- ) -> T {
- let old_lifetime_elision =
- std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
- let result = f(self);
- self.ctx.lifetime_elision = old_lifetime_elision;
- result
- }
-
- pub(crate) fn lower_ty_relative_path(
- &mut self,
- ty: Ty<'db>,
- // We need the original resolution to lower `Self::AssocTy` correctly
- res: Option<TypeNs>,
- infer_args: bool,
- ) -> (Ty<'db>, Option<TypeNs>) {
- let remaining_segments = self.segments.len() - self.current_segment_idx;
- match remaining_segments {
- 0 => (ty, res),
- 1 => {
- // resolve unselected assoc types
- (self.select_associated_type(res, infer_args), None)
- }
- _ => {
- // FIXME report error (ambiguous associated type)
- (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None)
- }
- }
- }
-
- fn prohibit_parenthesized_generic_args(&mut self) -> bool {
- if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
- match generic_args.parenthesized {
- GenericArgsParentheses::No => {}
- GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => {
- let segment = self.current_segment_u32();
- self.on_diagnostic(
- PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
- );
- return true;
- }
- }
- }
- false
- }
-
- // When calling this, the current segment is the resolved segment (we don't advance it yet).
- pub(crate) fn lower_partly_resolved_path(
- &mut self,
- resolution: TypeNs,
- infer_args: bool,
- ) -> (Ty<'db>, Option<TypeNs>) {
- let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
- tracing::debug!(?remaining_segments);
- let rem_seg_len = remaining_segments.len();
- tracing::debug!(?rem_seg_len);
-
- let ty = match resolution {
- TypeNs::TraitId(trait_) => {
- let ty = match remaining_segments.len() {
- 1 => {
- let trait_ref = self.lower_trait_ref_from_resolved_path(
- trait_,
- Ty::new_error(self.ctx.interner, ErrorGuaranteed),
- false,
- );
- tracing::debug!(?trait_ref);
- self.skip_resolved_segment();
- let segment = self.current_or_prev_segment;
- let trait_id = trait_ref.def_id.0;
- let found =
- trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
-
- tracing::debug!(?found);
- match found {
- Some(associated_ty) => {
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`trait_ref.substitution`).
- let substitution = self.substs_from_path_segment(
- associated_ty.into(),
- false,
- None,
- true,
- );
- let args = crate::next_solver::GenericArgs::new_from_iter(
- self.ctx.interner,
- trait_ref
- .args
- .iter()
- .chain(substitution.iter().skip(trait_ref.args.len())),
- );
- Ty::new_alias(
- self.ctx.interner,
- AliasTyKind::Projection,
- AliasTy::new_from_args(
- self.ctx.interner,
- associated_ty.into(),
- args,
- ),
- )
- }
- None => {
- // FIXME: report error (associated type not found)
- Ty::new_error(self.ctx.interner, ErrorGuaranteed)
- }
- }
- }
- 0 => {
- // Trait object type without dyn; this should be handled in upstream. See
- // `lower_path()`.
- stdx::never!("unexpected fully resolved trait path");
- Ty::new_error(self.ctx.interner, ErrorGuaranteed)
- }
- _ => {
- // FIXME report error (ambiguous associated type)
- Ty::new_error(self.ctx.interner, ErrorGuaranteed)
- }
- };
- return (ty, None);
- }
- TypeNs::GenericParam(param_id) => {
- let generics = self.ctx.generics();
- let idx = generics.type_or_const_param_idx(param_id.into());
- match idx {
- None => {
- never!("no matching generics");
- Ty::new_error(self.ctx.interner, ErrorGuaranteed)
- }
- Some(idx) => {
- let (pidx, param) = generics.iter().nth(idx).unwrap();
- assert_eq!(pidx, param_id.into());
- let p = match param {
- GenericParamDataRef::TypeParamData(p) => p,
- _ => unreachable!(),
- };
- self.ctx.type_param(
- param_id,
- idx as u32,
- p.name
- .as_ref()
- .map_or_else(|| sym::MISSING_NAME.clone(), |p| p.symbol().clone()),
- )
- }
- }
- }
- TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
- TypeNs::AdtSelfType(adt) => {
- let args = crate::next_solver::GenericArgs::identity_for_item(
- self.ctx.interner,
- adt.into(),
- );
- Ty::new_adt(self.ctx.interner, adt, args)
- }
-
- TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
- TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
- TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
- // FIXME: report error
- TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
- return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
- }
- };
-
- tracing::debug!(?ty);
-
- self.skip_resolved_segment();
- self.lower_ty_relative_path(ty, Some(resolution), infer_args)
- }
-
- fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
- let mut prohibit_generics_on_resolved = |reason| {
- if self.current_or_prev_segment.args_and_bindings.is_some() {
- let segment = self.current_segment_u32();
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment,
- reason,
- });
- }
- };
-
- match resolution {
- TypeNs::SelfType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- TypeNs::GenericParam(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
- }
- TypeNs::AdtSelfType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- TypeNs::BuiltinType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
- }
- TypeNs::ModuleId(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module)
- }
- TypeNs::AdtId(_)
- | TypeNs::EnumVariantId(_)
- | TypeNs::TypeAliasId(_)
- | TypeNs::TraitId(_) => {}
- }
- }
-
- pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
- let (res, unresolved) = self.resolve_path_in_type_ns()?;
- if unresolved.is_some() {
- return None;
- }
- Some(res)
- }
-
- #[tracing::instrument(skip(self), ret)]
- pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
- let (resolution, remaining_index, _, prefix_info) =
- self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?;
-
- let segments = self.segments;
- if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
- // `segments.is_empty()` can occur with `self`.
- return Some((resolution, remaining_index));
- }
-
- let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
- None if prefix_info.enum_variant => {
- (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
- }
- None => (segments.strip_last(), segments.len() - 1, None),
- Some(i) => (segments.take(i - 1), i - 1, None),
- };
-
- self.current_segment_idx = resolved_segment_idx;
- self.current_or_prev_segment =
- segments.get(resolved_segment_idx).expect("should have resolved segment");
-
- if matches!(self.path, Path::BarePath(..)) {
- // Bare paths cannot have generics, so skip them as an optimization.
- return Some((resolution, remaining_index));
- }
-
- for (i, mod_segment) in module_segments.iter().enumerate() {
- if mod_segment.args_and_bindings.is_some() {
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment: i as u32,
- reason: GenericArgsProhibitedReason::Module,
- });
- }
- }
-
- if let Some(enum_segment) = enum_segment
- && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
- && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
- {
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment: (enum_segment + 1) as u32,
- reason: GenericArgsProhibitedReason::EnumVariant,
- });
- }
-
- self.handle_type_ns_resolution(&resolution);
-
- Some((resolution, remaining_index))
- }
-
- pub(crate) fn resolve_path_in_value_ns(
- &mut self,
- hygiene_id: HygieneId,
- ) -> Option<ResolveValueResult> {
- let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
- self.ctx.db,
- self.path,
- hygiene_id,
- )?;
-
- let segments = self.segments;
- if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
- // `segments.is_empty()` can occur with `self`.
- return Some(res);
- }
-
- let (mod_segments, enum_segment, resolved_segment_idx) = match res {
- ResolveValueResult::Partial(_, unresolved_segment, _) => {
- (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
- }
- ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
- if prefix_info.enum_variant =>
- {
- (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
- }
- ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
- };
-
- self.current_segment_idx = resolved_segment_idx;
- self.current_or_prev_segment =
- segments.get(resolved_segment_idx).expect("should have resolved segment");
-
- for (i, mod_segment) in mod_segments.iter().enumerate() {
- if mod_segment.args_and_bindings.is_some() {
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment: i as u32,
- reason: GenericArgsProhibitedReason::Module,
- });
- }
- }
-
- if let Some(enum_segment) = enum_segment
- && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
- && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
- {
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment: (enum_segment + 1) as u32,
- reason: GenericArgsProhibitedReason::EnumVariant,
- });
- }
-
- match &res {
- ResolveValueResult::ValueNs(resolution, _) => {
- let resolved_segment_idx = self.current_segment_u32();
- let resolved_segment = self.current_or_prev_segment;
-
- let mut prohibit_generics_on_resolved = |reason| {
- if resolved_segment.args_and_bindings.is_some() {
- self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
- segment: resolved_segment_idx,
- reason,
- });
- }
- };
-
- match resolution {
- ValueNs::ImplSelf(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
- // E0109 (generic arguments provided for a type that doesn't accept them) for
- // consts and statics, presumably as a defense against future in which consts
- // and statics can be generic, or just because it was easier for rustc implementors.
- // That means we'll show the wrong error code. Because of us it's easier to do it
- // this way :)
- ValueNs::GenericParam(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
- }
- ValueNs::StaticId(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
- }
- ValueNs::LocalBinding(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
- }
- ValueNs::FunctionId(_)
- | ValueNs::StructId(_)
- | ValueNs::EnumVariantId(_)
- | ValueNs::ConstId(_) => {}
- }
- }
- ResolveValueResult::Partial(resolution, _, _) => {
- self.handle_type_ns_resolution(resolution);
- }
- };
- Some(res)
- }
-
- #[tracing::instrument(skip(self), ret)]
- fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
- let interner = self.ctx.interner;
- let Some(res) = res else {
- return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
- };
- let db = self.ctx.db;
- let def = self.ctx.def;
- let segment = self.current_or_prev_segment;
- let assoc_name = segment.name;
- let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
- if name != assoc_name {
- return None;
- }
-
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`t.substitution`).
- let substs =
- self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
-
- let substs = crate::next_solver::GenericArgs::new_from_iter(
- interner,
- t.args.iter().chain(substs.iter().skip(t.args.len())),
- );
-
- Some(Ty::new_alias(
- interner,
- AliasTyKind::Projection,
- AliasTy::new(interner, associated_ty.into(), substs),
- ))
- };
- named_associated_type_shorthand_candidates(
- interner,
- def,
- res,
- Some(assoc_name.clone()),
- check_alias,
- )
- .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
- }
-
- fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
- let generic_def = match typeable {
- TyDefId::BuiltinType(builtinty) => {
- return Ty::from_builtin_type(self.ctx.interner, builtinty);
- }
- TyDefId::AdtId(it) => it.into(),
- TyDefId::TypeAliasId(it) => it.into(),
- };
- let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
- let ty = ty_query(self.ctx.db, typeable);
- ty.instantiate(self.ctx.interner, args)
- }
-
- /// Collect generic arguments from a path into a `Substs`. See also
- /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
- pub(crate) fn substs_from_path(
- &mut self,
- // Note that we don't call `db.value_type(resolved)` here,
- // `ValueTyDefId` is just a convenient way to pass generics and
- // special-case enum variants
- resolved: ValueTyDefId,
- infer_args: bool,
- lowering_assoc_type_generics: bool,
- ) -> crate::next_solver::GenericArgs<'db> {
- let interner = self.ctx.interner;
- let prev_current_segment_idx = self.current_segment_idx;
- let prev_current_segment = self.current_or_prev_segment;
-
- let generic_def = match resolved {
- ValueTyDefId::FunctionId(it) => it.into(),
- ValueTyDefId::StructId(it) => it.into(),
- ValueTyDefId::UnionId(it) => it.into(),
- ValueTyDefId::ConstId(it) => it.into(),
- ValueTyDefId::StaticId(_) => {
- return crate::next_solver::GenericArgs::new_from_iter(interner, []);
- }
- ValueTyDefId::EnumVariantId(var) => {
- // the generic args for an enum variant may be either specified
- // on the segment referring to the enum, or on the segment
- // referring to the variant. So `Option::<T>::None` and
- // `Option::None::<T>` are both allowed (though the former is
- // FIXME: This isn't strictly correct, enum variants may be used not through the enum
- // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
- // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
- // if generics exist on the module and they don't match with the variant.
- // preferred). See also `def_ids_for_path_segments` in rustc.
- //
- // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
- // This simplifies the code a bit.
- let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
- let penultimate = self.segments.get(penultimate_idx);
- if let Some(penultimate) = penultimate
- && self.current_or_prev_segment.args_and_bindings.is_none()
- && penultimate.args_and_bindings.is_some()
- {
- self.current_segment_idx = penultimate_idx;
- self.current_or_prev_segment = penultimate;
- }
- var.lookup(self.ctx.db).parent.into()
- }
- };
- let result = self.substs_from_path_segment(
- generic_def,
- infer_args,
- None,
- lowering_assoc_type_generics,
- );
- self.current_segment_idx = prev_current_segment_idx;
- self.current_or_prev_segment = prev_current_segment;
- result
- }
-
- pub(crate) fn substs_from_path_segment(
- &mut self,
- def: GenericDefId,
- infer_args: bool,
- explicit_self_ty: Option<Ty<'db>>,
- lowering_assoc_type_generics: bool,
- ) -> crate::next_solver::GenericArgs<'db> {
- let old_lifetime_elision = self.ctx.lifetime_elision.clone();
-
- if let Some(args) = self.current_or_prev_segment.args_and_bindings
- && args.parenthesized != GenericArgsParentheses::No
- {
- let prohibit_parens = match def {
- GenericDefId::TraitId(trait_) => {
- // RTN is prohibited anyways if we got here.
- let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
- let is_fn_trait = self
- .ctx
- .db
- .trait_signature(trait_)
- .flags
- .contains(TraitFlags::RUSTC_PAREN_SUGAR);
- is_rtn || !is_fn_trait
- }
- _ => true,
- };
-
- if prohibit_parens {
- let segment = self.current_segment_u32();
- self.on_diagnostic(
- PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
- );
-
- return unknown_subst(self.ctx.interner, def);
- }
-
- // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
- self.ctx.lifetime_elision =
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
- }
-
- let result = self.substs_from_args_and_bindings(
- self.current_or_prev_segment.args_and_bindings,
- def,
- infer_args,
- explicit_self_ty,
- PathGenericsSource::Segment(self.current_segment_u32()),
- lowering_assoc_type_generics,
- self.ctx.lifetime_elision.clone(),
- );
- self.ctx.lifetime_elision = old_lifetime_elision;
- result
- }
-
- pub(super) fn substs_from_args_and_bindings(
- &mut self,
- args_and_bindings: Option<&GenericArgs>,
- def: GenericDefId,
- infer_args: bool,
- explicit_self_ty: Option<Ty<'db>>,
- generics_source: PathGenericsSource,
- lowering_assoc_type_generics: bool,
- lifetime_elision: LifetimeElisionKind<'db>,
- ) -> crate::next_solver::GenericArgs<'db> {
- struct LowererCtx<'a, 'b, 'c, 'db> {
- ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
- generics_source: PathGenericsSource,
- }
-
- impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
- fn report_len_mismatch(
- &mut self,
- def: GenericDefId,
- provided_count: u32,
- expected_count: u32,
- kind: IncorrectGenericsLenKind,
- ) {
- self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
- generics_source: self.generics_source,
- provided_count,
- expected_count,
- kind,
- def,
- });
- }
-
- fn report_arg_mismatch(
- &mut self,
- param_id: GenericParamId,
- arg_idx: u32,
- has_self_arg: bool,
- ) {
- self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
- generics_source: self.generics_source,
- param_id,
- arg_idx,
- has_self_arg,
- });
- }
-
- fn provided_kind(
- &mut self,
- param_id: GenericParamId,
- param: GenericParamDataRef<'_>,
- arg: &GenericArg,
- ) -> crate::next_solver::GenericArg<'db> {
- match (param, *arg) {
- (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
- self.ctx.ctx.lower_lifetime(lifetime).into()
- }
- (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
- self.ctx.ctx.lower_ty(type_ref).into()
- }
- (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
- let GenericParamId::ConstParamId(const_id) = param_id else {
- unreachable!("non-const param ID for const param");
- };
- self.ctx
- .ctx
- .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
- .into()
- }
- _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
- }
- }
-
- fn provided_type_like_const(
- &mut self,
- const_ty: Ty<'db>,
- arg: TypeLikeConst<'_>,
- ) -> crate::next_solver::Const<'db> {
- match arg {
- TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
- TypeLikeConst::Infer => unknown_const(const_ty),
- }
- }
-
- fn inferred_kind(
- &mut self,
- def: GenericDefId,
- param_id: GenericParamId,
- param: GenericParamDataRef<'_>,
- infer_args: bool,
- preceding_args: &[crate::next_solver::GenericArg<'db>],
- ) -> crate::next_solver::GenericArg<'db> {
- let default = || {
- self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
- convert_binder_to_early_binder(
- self.ctx.ctx.interner,
- def,
- default.to_nextsolver(self.ctx.ctx.interner),
- )
- .instantiate(self.ctx.ctx.interner, preceding_args)
- })
- };
- match param {
- GenericParamDataRef::LifetimeParamData(_) => {
- Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
- .into()
- }
- GenericParamDataRef::TypeParamData(param) => {
- if !infer_args
- && param.default.is_some()
- && let Some(default) = default()
- {
- return default;
- }
- Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
- }
- GenericParamDataRef::ConstParamData(param) => {
- if !infer_args
- && param.default.is_some()
- && let Some(default) = default()
- {
- return default;
- }
- let GenericParamId::ConstParamId(const_id) = param_id else {
- unreachable!("non-const param ID for const param");
- };
- unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
- }
- }
- }
-
- fn parent_arg(
- &mut self,
- param_id: GenericParamId,
- ) -> crate::next_solver::GenericArg<'db> {
- match param_id {
- GenericParamId::TypeParamId(_) => {
- Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
- }
- GenericParamId::ConstParamId(const_id) => {
- unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
- }
- GenericParamId::LifetimeParamId(_) => {
- Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
- .into()
- }
- }
- }
-
- fn report_elided_lifetimes_in_path(
- &mut self,
- def: GenericDefId,
- expected_count: u32,
- hard_error: bool,
- ) {
- self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
- generics_source: self.generics_source,
- def,
- expected_count,
- hard_error,
- });
- }
-
- fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
- self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
- generics_source: self.generics_source,
- def,
- expected_count,
- });
- }
-
- fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
- self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
- generics_source: self.generics_source,
- def,
- expected_count,
- });
- }
- }
-
- substs_from_args_and_bindings(
- self.ctx.db,
- self.ctx.store,
- args_and_bindings,
- def,
- infer_args,
- lifetime_elision,
- lowering_assoc_type_generics,
- explicit_self_ty,
- &mut LowererCtx { ctx: self, generics_source },
- )
- }
-
- pub(crate) fn lower_trait_ref_from_resolved_path(
- &mut self,
- resolved: TraitId,
- explicit_self_ty: Ty<'db>,
- infer_args: bool,
- ) -> TraitRef<'db> {
- let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
- TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
- }
-
- fn trait_ref_substs_from_path(
- &mut self,
- resolved: TraitId,
- explicit_self_ty: Ty<'db>,
- infer_args: bool,
- ) -> crate::next_solver::GenericArgs<'db> {
- self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
- }
-
- pub(super) fn assoc_type_bindings_from_type_bound<'c>(
- mut self,
- trait_ref: TraitRef<'db>,
- ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
- let interner = self.ctx.interner;
- self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
- args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
- let found = associated_type_by_name_including_super_traits(
- self.ctx.db,
- trait_ref,
- &binding.name,
- );
- let (super_trait_ref, associated_ty) = match found {
- None => return SmallVec::new(),
- Some(t) => t,
- };
- let args =
- self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`super_trait_ref.substitution`).
- this.substs_from_args_and_bindings(
- binding.args.as_ref(),
- associated_ty.into(),
- false, // this is not relevant
- Some(super_trait_ref.self_ty()),
- PathGenericsSource::AssocType {
- segment: this.current_segment_u32(),
- assoc_type: binding_idx as u32,
- },
- false,
- this.ctx.lifetime_elision.clone(),
- )
- });
- let args = crate::next_solver::GenericArgs::new_from_iter(
- interner,
- super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
- );
- let projection_term =
- AliasTerm::new_from_args(interner, associated_ty.into(), args);
- let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
- binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
- );
- if let Some(type_ref) = binding.type_ref {
- let lifetime_elision =
- if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
- // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
- LifetimeElisionKind::for_fn_ret(self.ctx.interner)
- } else {
- self.ctx.lifetime_elision.clone()
- };
- self.with_lifetime_elision(lifetime_elision, |this| {
- match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
- (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
- (
- _,
- ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
- ) => {
- let ty = this.ctx.lower_ty(type_ref);
- let pred = Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Projection(
- ProjectionPredicate {
- projection_term,
- term: ty.into(),
- },
- ),
- )),
- ));
- predicates.push(pred);
- }
- }
- })
- }
- for bound in binding.bounds.iter() {
- predicates.extend(self.ctx.lower_type_bound(
- bound,
- Ty::new_alias(
- self.ctx.interner,
- AliasTyKind::Projection,
- AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
- ),
- false,
- ));
- }
- predicates
- })
- })
- }
-}
-
-/// A const that were parsed like a type.
-pub(crate) enum TypeLikeConst<'a> {
- Infer,
- Path(&'a Path),
-}
-
-pub(crate) trait GenericArgsLowerer<'db> {
- fn report_elided_lifetimes_in_path(
- &mut self,
- def: GenericDefId,
- expected_count: u32,
- hard_error: bool,
- );
-
- fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
-
- fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
-
- fn report_len_mismatch(
- &mut self,
- def: GenericDefId,
- provided_count: u32,
- expected_count: u32,
- kind: IncorrectGenericsLenKind,
- );
-
- fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
-
- fn provided_kind(
- &mut self,
- param_id: GenericParamId,
- param: GenericParamDataRef<'_>,
- arg: &GenericArg,
- ) -> crate::next_solver::GenericArg<'db>;
-
- fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
- -> Const<'db>;
-
- fn inferred_kind(
- &mut self,
- def: GenericDefId,
- param_id: GenericParamId,
- param: GenericParamDataRef<'_>,
- infer_args: bool,
- preceding_args: &[crate::next_solver::GenericArg<'db>],
- ) -> crate::next_solver::GenericArg<'db>;
-
- fn parent_arg(&mut self, param_id: GenericParamId) -> crate::next_solver::GenericArg<'db>;
-}
-
-/// Returns true if there was an error.
-fn check_generic_args_len<'db>(
- args_and_bindings: Option<&GenericArgs>,
- def: GenericDefId,
- def_generics: &Generics,
- infer_args: bool,
- lifetime_elision: &LifetimeElisionKind<'db>,
- lowering_assoc_type_generics: bool,
- ctx: &mut impl GenericArgsLowerer<'db>,
-) -> bool {
- let mut had_error = false;
-
- let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
- if let Some(args_and_bindings) = args_and_bindings {
- let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
- for arg in args_no_self {
- match arg {
- GenericArg::Lifetime(_) => provided_lifetimes_count += 1,
- GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1,
- }
- }
- }
-
- let lifetime_args_len = def_generics.len_lifetimes_self();
- if provided_lifetimes_count == 0
- && lifetime_args_len > 0
- && (!lowering_assoc_type_generics || infer_args)
- {
- // In generic associated types, we never allow inferring the lifetimes, but only in type context, that is
- // when `infer_args == false`. In expression/pattern context we always allow inferring them, even for GATs.
- match lifetime_elision {
- &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
- ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
- had_error |= report_in_path;
- }
- LifetimeElisionKind::AnonymousReportError => {
- ctx.report_missing_lifetime(def, lifetime_args_len as u32);
- had_error = true
- }
- LifetimeElisionKind::ElisionFailure => {
- ctx.report_elision_failure(def, lifetime_args_len as u32);
- had_error = true;
- }
- LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
- // FIXME: Check there are other lifetimes in scope, and error/lint.
- }
- LifetimeElisionKind::Elided(_) => {
- ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
- }
- LifetimeElisionKind::Infer => {
- // Allow eliding lifetimes.
- }
- }
- } else if lifetime_args_len != provided_lifetimes_count {
- ctx.report_len_mismatch(
- def,
- provided_lifetimes_count as u32,
- lifetime_args_len as u32,
- IncorrectGenericsLenKind::Lifetimes,
- );
- had_error = true;
- }
-
- let defaults_count =
- def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
- let named_type_and_const_params_count = def_generics
- .iter_self_type_or_consts()
- .filter(|(_, param)| match param {
- TypeOrConstParamData::TypeParamData(param) => {
- param.provenance == TypeParamProvenance::TypeParamList
- }
- TypeOrConstParamData::ConstParamData(_) => true,
- })
- .count();
- let expected_max = named_type_and_const_params_count;
- let expected_min =
- if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
- if provided_types_and_consts_count < expected_min
- || expected_max < provided_types_and_consts_count
- {
- ctx.report_len_mismatch(
- def,
- provided_types_and_consts_count as u32,
- named_type_and_const_params_count as u32,
- IncorrectGenericsLenKind::TypesAndConsts,
- );
- had_error = true;
- }
-
- had_error
-}
-
-pub(crate) fn substs_from_args_and_bindings<'db>(
- db: &'db dyn HirDatabase,
- store: &ExpressionStore,
- args_and_bindings: Option<&GenericArgs>,
- def: GenericDefId,
- mut infer_args: bool,
- lifetime_elision: LifetimeElisionKind<'db>,
- lowering_assoc_type_generics: bool,
- explicit_self_ty: Option<Ty<'db>>,
- ctx: &mut impl GenericArgsLowerer<'db>,
-) -> crate::next_solver::GenericArgs<'db> {
- let interner = DbInterner::new_with(db, None, None);
-
- tracing::debug!(?args_and_bindings);
-
- // Order is
- // - Parent parameters
- // - Optional Self parameter
- // - Lifetime parameters
- // - Type or Const parameters
- let def_generics = generics(db, def);
- let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
-
- // We do not allow inference if there are specified args, i.e. we do not allow partial inference.
- let has_non_lifetime_args =
- args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
- infer_args &= !has_non_lifetime_args;
-
- let had_count_error = check_generic_args_len(
- args_and_bindings,
- def,
- &def_generics,
- infer_args,
- &lifetime_elision,
- lowering_assoc_type_generics,
- ctx,
- );
-
- let mut substs = Vec::with_capacity(def_generics.len());
-
- substs.extend(def_generics.iter_parent_id().map(|id| ctx.parent_arg(id)));
-
- let mut args = args_slice.iter().enumerate().peekable();
- let mut params = def_generics.iter_self().peekable();
-
- // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
- // If we later encounter a lifetime, we know that the arguments were provided in the
- // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
- // inferred, so we can use it for diagnostics later.
- let mut force_infer_lt = None;
-
- let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
- // First, handle `Self` parameter. Consume it from the args if provided, otherwise from `explicit_self_ty`,
- // and lastly infer it.
- if let Some(&(
- self_param_id,
- self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
- provenance: TypeParamProvenance::TraitSelf,
- ..
- }),
- )) = params.peek()
- {
- let self_ty = if has_self_arg {
- let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
- ctx.provided_kind(self_param_id, self_param, self_ty)
- } else {
- explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
- ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
- })
- };
- params.next();
- substs.push(self_ty);
- }
-
- loop {
- // We're going to iterate through the generic arguments that the user
- // provided, matching them with the generic parameters we expect.
- // Mismatches can occur as a result of elided lifetimes, or for malformed
- // input. We try to handle both sensibly.
- match (args.peek(), params.peek()) {
- (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
- (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
- if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
- {
- // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
- // we will handle it as if it was specified, instead of inferring it.
- substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
- params.next();
- }
- (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
- | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
- | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
- substs.push(ctx.provided_kind(param_id, param, arg));
- args.next();
- params.next();
- }
- (
- GenericArg::Type(_) | GenericArg::Const(_),
- GenericParamDataRef::LifetimeParamData(_),
- ) => {
- // We expected a lifetime argument, but got a type or const
- // argument. That means we're inferring the lifetime.
- substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
- params.next();
- force_infer_lt = Some((arg_idx as u32, param_id));
- }
- (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
- if let Some(konst) = type_looks_like_const(store, *type_ref) {
- let GenericParamId::ConstParamId(param_id) = param_id else {
- panic!("unmatching param kinds");
- };
- let const_ty = const_param_ty_query(db, param_id);
- substs.push(ctx.provided_type_like_const(const_ty, konst).into());
- args.next();
- params.next();
- } else {
- // See the `_ => { ... }` branch.
- if !had_count_error {
- ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
- }
- while args.next().is_some() {}
- }
- }
- _ => {
- // We expected one kind of parameter, but the user provided
- // another. This is an error. However, if we already know that
- // the arguments don't match up with the parameters, we won't issue
- // an additional error, as the user already knows what's wrong.
- if !had_count_error {
- ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
- }
-
- // We've reported the error, but we want to make sure that this
- // problem doesn't bubble down and create additional, irrelevant
- // errors. In this case, we're simply going to ignore the argument
- // and any following arguments. The rest of the parameters will be
- // inferred.
- while args.next().is_some() {}
- }
- },
-
- (Some(&(_, arg)), None) => {
- // We should never be able to reach this point with well-formed input.
- // There are two situations in which we can encounter this issue.
- //
- // 1. The number of arguments is incorrect. In this case, an error
- // will already have been emitted, and we can ignore it.
- // 2. We've inferred some lifetimes, which have been provided later (i.e.
- // after a type or const). We want to throw an error in this case.
- if !had_count_error {
- assert!(
- matches!(arg, GenericArg::Lifetime(_)),
- "the only possible situation here is incorrect lifetime order"
- );
- let (provided_arg_idx, param_id) =
- force_infer_lt.expect("lifetimes ought to have been inferred");
- ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
- }
-
- break;
- }
-
- (None, Some(&(param_id, param))) => {
- // If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
- let param = if let GenericParamId::LifetimeParamId(_) = param_id {
- match &lifetime_elision {
- LifetimeElisionKind::ElisionFailure
- | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
- | LifetimeElisionKind::AnonymousReportError => {
- assert!(had_count_error);
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
- }
- LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
- Region::new_static(interner).into()
- }
- LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
- | LifetimeElisionKind::Infer => {
- // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
- // (but this will probably be done in hir-def lowering instead).
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
- }
- }
- } else {
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
- };
- substs.push(param);
- params.next();
- }
-
- (None, None) => break,
- }
- }
-
- crate::next_solver::GenericArgs::new_from_iter(interner, substs)
-}
-
-fn type_looks_like_const(
- store: &ExpressionStore,
- type_ref: TypeRefId,
-) -> Option<TypeLikeConst<'_>> {
- // A path/`_` const will be parsed as a type, instead of a const, because when parsing/lowering
- // in hir-def we don't yet know the expected argument kind. rustc does this a bit differently,
- // when lowering to HIR it resolves the path, and if it doesn't resolve to the type namespace
- // it is lowered as a const. Our behavior could deviate from rustc when the value is resolvable
- // in both the type and value namespaces, but I believe we only allow more code.
- let type_ref = &store[type_ref];
- match type_ref {
- TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
- TypeRef::Placeholder => Some(TypeLikeConst::Infer),
- _ => None,
- }
-}
-
-fn unknown_subst<'db>(
- interner: DbInterner<'db>,
- def: impl Into<GenericDefId>,
-) -> crate::next_solver::GenericArgs<'db> {
- let params = generics(interner.db(), def.into());
- crate::next_solver::GenericArgs::new_from_iter(
- interner,
- params.iter_id().map(|id| match id {
- GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
- GenericParamId::ConstParamId(id) => {
- unknown_const_as_generic(const_param_ty_query(interner.db(), id))
- }
- GenericParamId::LifetimeParamId(_) => {
- crate::next_solver::Region::error(interner).into()
- }
- }),
- )
-}
diff --git a/crates/hir-ty/src/mapping.rs b/crates/hir-ty/src/mapping.rs
deleted file mode 100644
index 5125a38..0000000
--- a/crates/hir-ty/src/mapping.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-//! This module contains the implementations of the `ToChalk` trait, which
-//! handles conversion between our data types and their corresponding types in
-//! Chalk (in both directions); plus some helper functions for more specialized
-//! conversions.
-
-use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId};
-use salsa::{
- Id,
- plumbing::{AsId, FromId},
-};
-
-use crate::{
- AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId, Interner, OpaqueTyId,
- PlaceholderIndex, chalk_db,
- db::{HirDatabase, InternedLifetimeParamId, InternedTypeOrConstParamId},
-};
-
-pub trait ToChalk {
- type Chalk;
- fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
- fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
-}
-
-pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T
-where
- T: ToChalk<Chalk = ChalkT>,
-{
- T::from_chalk(db, chalk)
-}
-
-impl ToChalk for hir_def::ImplId {
- type Chalk = chalk_db::ImplId;
-
- fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId {
- chalk_ir::ImplId(self.as_id())
- }
-
- fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId {
- FromId::from_id(impl_id.0.as_id())
- }
-}
-
-impl ToChalk for CallableDefId {
- type Chalk = FnDefId;
-
- fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId {
- chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self))
- }
-
- fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
- salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa())
- }
-}
-
-impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
- fn from(id: OpaqueTyId) -> Self {
- FromId::from_id(id.0)
- }
-}
-
-impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
- fn from(id: crate::db::InternedOpaqueTyId) -> Self {
- chalk_ir::OpaqueTyId(id.as_id())
- }
-}
-
-impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
- fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
- FromId::from_id(id.0)
- }
-}
-
-impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
- fn from(id: crate::db::InternedClosureId) -> Self {
- chalk_ir::ClosureId(id.as_id())
- }
-}
-
-impl From<chalk_ir::CoroutineId<Interner>> for crate::db::InternedCoroutineId {
- fn from(id: chalk_ir::CoroutineId<Interner>) -> Self {
- Self::from_id(id.0)
- }
-}
-
-impl From<crate::db::InternedCoroutineId> for chalk_ir::CoroutineId<Interner> {
- fn from(id: crate::db::InternedCoroutineId) -> Self {
- chalk_ir::CoroutineId(id.as_id())
- }
-}
-
-pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
- chalk_ir::ForeignDefId(id.as_id())
-}
-
-pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
- FromId::from_id(id.0)
-}
-
-pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId {
- chalk_ir::AssocTypeId(id.as_id())
-}
-
-pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
- FromId::from_id(id.0)
-}
-
-pub fn from_placeholder_idx(
- db: &dyn HirDatabase,
- idx: PlaceholderIndex,
-) -> (TypeOrConstParamId, u32) {
- assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
- // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
- let interned_id =
- InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
- interned_id.loc(db)
-}
-
-pub fn to_placeholder_idx(
- db: &dyn HirDatabase,
- id: TypeOrConstParamId,
- idx: u32,
-) -> PlaceholderIndex {
- let interned_id = InternedTypeOrConstParamId::new(db, (id, idx));
- PlaceholderIndex {
- ui: chalk_ir::UniverseIndex::ROOT,
- idx: interned_id.as_id().index() as usize,
- }
-}
-
-pub fn to_placeholder_idx_no_index(
- db: &dyn HirDatabase,
- id: TypeOrConstParamId,
-) -> PlaceholderIndex {
- let index = crate::generics::generics(db, id.parent)
- .type_or_const_param_idx(id)
- .expect("param not found");
- to_placeholder_idx(db, id, index as u32)
-}
-
-pub fn lt_from_placeholder_idx(
- db: &dyn HirDatabase,
- idx: PlaceholderIndex,
-) -> (LifetimeParamId, u32) {
- assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
- // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
- let interned_id =
- InternedLifetimeParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
- interned_id.loc(db)
-}
-
-pub fn lt_to_placeholder_idx(
- db: &dyn HirDatabase,
- id: LifetimeParamId,
- idx: u32,
-) -> PlaceholderIndex {
- let interned_id = InternedLifetimeParamId::new(db, (id, idx));
- PlaceholderIndex {
- ui: chalk_ir::UniverseIndex::ROOT,
- idx: interned_id.as_id().index() as usize,
- }
-}
-
-pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
- chalk_ir::TraitId(id.as_id())
-}
-
-pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
- FromId::from_id(id.0)
-}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 06c7cdd..cec6356 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -25,10 +25,8 @@
use stdx::never;
use triomphe::Arc;
-use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::infer::select::ImplSource;
use crate::{
- TraitEnvironment, TyBuilder,
+ TraitEnvironment,
autoderef::{self, AutoderefKind},
db::HirDatabase,
infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
@@ -37,7 +35,8 @@
Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId,
TraitRef, Ty, TyKind, TypingMode,
infer::{
- DbInternerInferExt, DefineOpaqueTypes,
+ DbInternerInferExt, InferCtxt,
+ select::ImplSource,
traits::{Obligation, ObligationCause, PredicateObligation},
},
obligation_ctxt::ObligationCtxt,
@@ -1597,9 +1596,9 @@
return IsValidCandidate::NotVisible;
}
let self_ty_matches = table.run_in_snapshot(|table| {
- let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
- .fill_with_inference_vars(table)
- .build(table.interner());
+ let impl_args = table.fresh_args_for_item(impl_id.into());
+ let expected_self_ty =
+ db.impl_self_ty(impl_id).instantiate(table.interner(), impl_args);
table.unify(expected_self_ty, self_ty)
});
if !self_ty_matches {
@@ -1654,7 +1653,7 @@
let res = table
.infer_ctxt
.at(&ObligationCause::dummy(), table.trait_env.env)
- .relate(DefineOpaqueTypes::No, expected_receiver, variance, receiver_ty);
+ .relate(expected_receiver, variance, receiver_ty);
let Ok(infer_ok) = res else {
return IsValidCandidate::No;
};
@@ -1727,7 +1726,7 @@
// We need to consider the bounds on the impl to distinguish functions of the same name
// for a type.
- let predicates = db.generic_predicates_ns(impl_id.into());
+ let predicates = db.generic_predicates(impl_id.into());
let Some(predicates) = predicates.instantiate(table.interner(), impl_subst) else {
return IsValidCandidate::Yes;
};
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index 936895f..7aebe17 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -196,7 +196,7 @@
},
ProjectionElem::Field(Either::Left(f)) => match base.kind() {
TyKind::Adt(_, subst) => {
- db.field_types_ns(f.parent)[f.local_id].instantiate(interner, subst)
+ db.field_types(f.parent)[f.local_id].instantiate(interner, subst)
}
ty => {
never!("Only adt has field, found {:?}", ty);
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 444336c..6e62bcb 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1696,7 +1696,7 @@
if let TyKind::Adt(adt_ef, subst) = kind
&& let AdtId::StructId(struct_id) = adt_ef.def_id().0
{
- let field_types = self.db.field_types_ns(struct_id.into());
+ let field_types = self.db.field_types(struct_id.into());
if let Some(ty) =
field_types.iter().last().map(|it| it.1.instantiate(self.interner(), subst))
{
@@ -1775,9 +1775,9 @@
else {
not_supported!("unsizing struct without field");
};
- let target_last_field = self.db.field_types_ns(id.into())[last_field]
+ let target_last_field = self.db.field_types(id.into())[last_field]
.instantiate(self.interner(), target_subst);
- let current_last_field = self.db.field_types_ns(id.into())[last_field]
+ let current_last_field = self.db.field_types(id.into())[last_field]
.instantiate(self.interner(), current_subst);
return self.unsizing_ptr_from_addr(
target_last_field,
@@ -2268,7 +2268,7 @@
AdtId::StructId(s) => {
let data = s.fields(this.db);
let layout = this.layout(ty)?;
- let field_types = this.db.field_types_ns(s.into());
+ let field_types = this.db.field_types(s.into());
for (f, _) in data.fields().iter() {
let offset = layout
.fields
@@ -2296,7 +2296,7 @@
e,
) {
let data = v.fields(this.db);
- let field_types = this.db.field_types_ns(v.into());
+ let field_types = this.db.field_types(v.into());
for (f, _) in data.fields().iter() {
let offset =
l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
@@ -2373,7 +2373,7 @@
}
TyKind::Adt(id, args) => match id.def_id().0 {
AdtId::StructId(s) => {
- for (i, (_, ty)) in self.db.field_types_ns(s.into()).iter().enumerate() {
+ for (i, (_, ty)) in self.db.field_types(s.into()).iter().enumerate() {
let offset = layout.fields.offset(i).bytes_usize();
let ty = ty.instantiate(self.interner(), args);
self.patch_addresses(
@@ -2394,7 +2394,7 @@
self.read_memory(addr, layout.size.bytes_usize())?,
e,
) {
- for (i, (_, ty)) in self.db.field_types_ns(ev.into()).iter().enumerate() {
+ for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() {
let offset = layout.fields.offset(i).bytes_usize();
let ty = ty.instantiate(self.interner(), args);
self.patch_addresses(
@@ -2895,7 +2895,7 @@
let variant_fields = s.fields(self.db);
match variant_fields.shape {
FieldsShape::Record | FieldsShape::Tuple => {
- let field_types = self.db.field_types_ns(s.into());
+ let field_types = self.db.field_types(s.into());
for (field, _) in variant_fields.fields().iter() {
let offset = layout
.fields
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index c45ae9d..4b1adec 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -1383,7 +1383,7 @@
AdtId::StructId(s) => s,
_ => not_supported!("unsized enum or union"),
};
- let field_types = self.db.field_types_ns(id.into());
+ let field_types = self.db.field_types(id.into());
let last_field_ty =
field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst);
let sized_part_size =
diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs
index ade94b9..4c64a70 100644
--- a/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -34,7 +34,7 @@
let Some((first_field, _)) = fields.iter().next() else {
not_supported!("simd type with no field");
};
- let field_ty = self.db.field_types_ns(id.into())[first_field]
+ let field_ty = self.db.field_types(id.into())[first_field]
.instantiate(self.interner(), subst);
return Ok((fields.len(), field_ty));
}
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 4eb4aa9..f242115 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -636,16 +636,13 @@
);
}
-#[ignore = "
-FIXME(next-solver):
-This does not work currently because I replaced homemade selection with selection by the trait solver;
-This will work once we implement `Interner::impl_specializes()` properly.
-"]
#[test]
fn specialization_array_clone() {
check_pass(
r#"
//- minicore: copy, derive, slice, index, coerce_unsized, panic
+#![feature(min_specialization)]
+
impl<T: Clone, const N: usize> Clone for [T; N] {
#[inline]
fn clone(&self) -> Self {
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 92f9cd4..1439c43 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -43,7 +43,6 @@
next_solver::{
Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst,
infer::{DbInternerInferExt, InferCtxt},
- mapping::NextSolverToChalk,
},
traits::FnTrait,
};
@@ -303,6 +302,7 @@
let resolver = owner.resolver(db);
let env = db.trait_environment_for_body(owner);
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+ // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
MirLowerCtx {
@@ -1766,8 +1766,8 @@
fn is_uninhabited(&self, expr_id: ExprId) -> bool {
is_ty_uninhabited_from(
- self.db,
- &self.infer[expr_id].to_chalk(self.interner()),
+ &self.infcx,
+ self.infer[expr_id],
self.owner.module(self.db),
self.env.clone(),
)
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index e46edb8..0c5a649 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -118,10 +118,10 @@
Binding(Name, LocalId<'db>),
}
-impl<'db> HirDisplay for LocalName<'db> {
+impl<'db> HirDisplay<'db> for LocalName<'db> {
fn hir_fmt(
&self,
- f: &mut crate::display::HirFormatter<'_>,
+ f: &mut crate::display::HirFormatter<'_, 'db>,
) -> Result<(), crate::display::HirDisplayError> {
match self {
LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())),
@@ -489,7 +489,7 @@
}
}
- fn hir_display<'b, T: HirDisplay>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T>
+ fn hir_display<'b, T: HirDisplay<'db>>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T>
where
'db: 'b,
{
diff --git a/crates/hir-ty/src/next_solver.rs b/crates/hir-ty/src/next_solver.rs
index 776e0d9..8c52a84 100644
--- a/crates/hir-ty/src/next_solver.rs
+++ b/crates/hir-ty/src/next_solver.rs
@@ -1,5 +1,4 @@
//! Things relevant to the next trait solver.
-#![allow(unused, unreachable_pub)]
pub mod abi;
mod consts;
@@ -12,7 +11,6 @@
pub(crate) mod inspect;
pub mod interner;
mod ir_print;
-pub mod mapping;
pub mod normalize;
pub mod obligation_ctxt;
mod opaques;
@@ -33,7 +31,7 @@
pub use solver::*;
pub use ty::*;
-pub use crate::lower_nextsolver::ImplTraitIdx;
+pub use crate::lower::ImplTraitIdx;
pub use rustc_ast_ir::Mutability;
pub type Binder<'db, T> = rustc_type_ir::Binder<DbInterner<'db>, T>;
diff --git a/crates/hir-ty/src/next_solver/consts.rs b/crates/hir-ty/src/next_solver/consts.rs
index 2fc1fc4..926dbdc 100644
--- a/crates/hir-ty/src/next_solver/consts.rs
+++ b/crates/hir-ty/src/next_solver/consts.rs
@@ -2,21 +2,20 @@
use std::hash::Hash;
-use hir_def::{ConstParamId, TypeOrConstParamId};
-use intern::{Interned, Symbol};
+use hir_def::ConstParamId;
use macros::{TypeFoldable, TypeVisitable};
-use rustc_ast_ir::{try_visit, visit::VisitorResult};
+use rustc_ast_ir::visit::VisitorResult;
use rustc_type_ir::{
- BoundVar, DebruijnIndex, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable,
- TypeSuperVisitable, TypeVisitable, TypeVisitableExt, WithCachedTypeInfo,
+ BoundVar, BoundVarIndexKind, ConstVid, DebruijnIndex, FlagComputation, Flags, InferConst,
+ TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ WithCachedTypeInfo,
inherent::{IntoKind, ParamEnv as _, PlaceholderLike, SliceLike},
relate::Relate,
};
use crate::{
- ConstScalar, MemoryMap,
- interner::InternedWrapperNoDebug,
- next_solver::{ClauseKind, ParamEnv},
+ MemoryMap,
+ next_solver::{ClauseKind, ParamEnv, interner::InternedWrapperNoDebug},
};
use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty};
@@ -51,11 +50,11 @@
}
pub fn error(interner: DbInterner<'db>) -> Self {
- Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
+ Const::new(interner, ConstKind::Error(ErrorGuaranteed))
}
pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self {
- Const::new(interner, rustc_type_ir::ConstKind::Param(param))
+ Const::new(interner, ConstKind::Param(param))
}
pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst) -> Self {
@@ -63,7 +62,7 @@
}
pub fn new_bound(interner: DbInterner<'db>, index: DebruijnIndex, bound: BoundConst) -> Self {
- Const::new(interner, ConstKind::Bound(index, bound))
+ Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(index), bound))
}
pub fn new_valtree(
@@ -82,7 +81,11 @@
}
pub fn is_ct_infer(&self) -> bool {
- matches!(&self.inner().internee, ConstKind::Infer(_))
+ matches!(self.kind(), ConstKind::Infer(_))
+ }
+
+ pub fn is_error(&self) -> bool {
+ matches!(self.kind(), ConstKind::Error(_))
}
pub fn is_trivially_wf(self) -> bool {
@@ -338,28 +341,34 @@
}
impl<'db> rustc_type_ir::inherent::Const<DbInterner<'db>> for Const<'db> {
- fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferConst) -> Self {
+ fn new_infer(interner: DbInterner<'db>, var: InferConst) -> Self {
Const::new(interner, ConstKind::Infer(var))
}
- fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::ConstVid) -> Self {
- Const::new(interner, ConstKind::Infer(rustc_type_ir::InferConst::Var(var)))
+ fn new_var(interner: DbInterner<'db>, var: ConstVid) -> Self {
+ Const::new(interner, ConstKind::Infer(InferConst::Var(var)))
}
- fn new_bound(
- interner: DbInterner<'db>,
- debruijn: rustc_type_ir::DebruijnIndex,
- var: BoundConst,
- ) -> Self {
- Const::new(interner, ConstKind::Bound(debruijn, var))
+ fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundConst) -> Self {
+ Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
}
- fn new_anon_bound(
+ fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
+ Const::new(
+ interner,
+ ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), BoundConst { var }),
+ )
+ }
+
+ fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
+ Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Canonical, BoundConst { var }))
+ }
+
+ fn new_placeholder(
interner: DbInterner<'db>,
- debruijn: rustc_type_ir::DebruijnIndex,
- var: rustc_type_ir::BoundVar,
+ param: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderConst,
) -> Self {
- Const::new(interner, ConstKind::Bound(debruijn, BoundConst { var }))
+ Const::new(interner, ConstKind::Placeholder(param))
}
fn new_unevaluated(
@@ -376,13 +385,6 @@
fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self {
Const::new(interner, ConstKind::Error(guar))
}
-
- fn new_placeholder(
- interner: DbInterner<'db>,
- param: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderConst,
- ) -> Self {
- Const::new(interner, ConstKind::Placeholder(param))
- }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -425,7 +427,7 @@
impl<'db> Relate<DbInterner<'db>> for ExprConst {
fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
- relation: &mut R,
+ _relation: &mut R,
a: Self,
b: Self,
) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index 789be3b..0ff0b08 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -1,8 +1,8 @@
//! Definition of `SolverDefId`
use hir_def::{
- AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId,
- ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
+ AdtId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
+ GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
};
use rustc_type_ir::inherent;
use stdx::impl_from;
@@ -29,6 +29,8 @@
InternedClosureId(InternedClosureId),
InternedCoroutineId(InternedCoroutineId),
InternedOpaqueTyId(InternedOpaqueTyId),
+ EnumVariantId(EnumVariantId),
+ // FIXME(next-solver): Do we need the separation of `Ctor`? It duplicates some variants.
Ctor(Ctor),
}
@@ -73,6 +75,16 @@
SolverDefId::InternedOpaqueTyId(id) => {
f.debug_tuple("InternedOpaqueTyId").field(&id).finish()
}
+ SolverDefId::EnumVariantId(id) => {
+ let parent_enum = id.loc(db).parent;
+ f.debug_tuple("EnumVariantId")
+ .field(&format_args!(
+ "\"{}::{}\"",
+ db.enum_signature(parent_enum).name.as_str(),
+ parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str()
+ ))
+ .finish()
+ }
SolverDefId::Ctor(Ctor::Struct(id)) => {
f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish()
}
@@ -101,6 +113,7 @@
InternedClosureId,
InternedCoroutineId,
InternedOpaqueTyId,
+ EnumVariantId,
Ctor
for SolverDefId
);
@@ -129,8 +142,20 @@
}
}
+impl From<DefWithBodyId> for SolverDefId {
+ #[inline]
+ fn from(value: DefWithBodyId) -> Self {
+ match value {
+ DefWithBodyId::FunctionId(id) => id.into(),
+ DefWithBodyId::StaticId(id) => id.into(),
+ DefWithBodyId::ConstId(id) => id.into(),
+ DefWithBodyId::VariantId(id) => id.into(),
+ }
+ }
+}
+
impl TryFrom<SolverDefId> for GenericDefId {
- type Error = SolverDefId;
+ type Error = ();
fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
Ok(match value {
@@ -141,10 +166,11 @@
SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id),
SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id),
SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id),
- SolverDefId::InternedClosureId(_) => return Err(value),
- SolverDefId::InternedCoroutineId(_) => return Err(value),
- SolverDefId::InternedOpaqueTyId(_) => return Err(value),
- SolverDefId::Ctor(_) => return Err(value),
+ SolverDefId::InternedClosureId(_)
+ | SolverDefId::InternedCoroutineId(_)
+ | SolverDefId::InternedOpaqueTyId(_)
+ | SolverDefId::EnumVariantId(_)
+ | SolverDefId::Ctor(_) => return Err(()),
})
}
}
@@ -185,7 +211,7 @@
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- std::fmt::Debug::fmt(&self.0, f)
+ std::fmt::Debug::fmt(&SolverDefId::from(self.0), f)
}
}
diff --git a/crates/hir-ty/src/next_solver/fold.rs b/crates/hir-ty/src/next_solver/fold.rs
index a42fdb0..f776b6e 100644
--- a/crates/hir-ty/src/next_solver/fold.rs
+++ b/crates/hir-ty/src/next_solver/fold.rs
@@ -1,9 +1,8 @@
//! Fold impls for the next-trait-solver.
use rustc_type_ir::{
- BoundVar, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable,
- TypeVisitableExt,
- inherent::{IntoKind, Region as _},
+ BoundVarIndexKind, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitableExt, inherent::IntoKind,
};
use crate::next_solver::BoundConst;
@@ -55,7 +54,7 @@
}
impl<'db, D: BoundVarReplacerDelegate<'db>> BoundVarReplacer<'db, D> {
- pub fn new(tcx: DbInterner<'db>, delegate: D) -> Self {
+ pub(crate) fn new(tcx: DbInterner<'db>, delegate: D) -> Self {
BoundVarReplacer { interner: tcx, current_index: DebruijnIndex::ZERO, delegate }
}
}
@@ -80,7 +79,9 @@
fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
match t.kind() {
- TyKind::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
+ TyKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
+ if debruijn == self.current_index =>
+ {
let ty = self.delegate.replace_ty(bound_ty);
debug_assert!(!ty.has_vars_bound_above(DebruijnIndex::ZERO));
rustc_type_ir::shift_vars(self.interner, ty, self.current_index.as_u32())
@@ -97,9 +98,12 @@
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
match r.kind() {
- RegionKind::ReBound(debruijn, br) if debruijn == self.current_index => {
+ RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), br)
+ if debruijn == self.current_index =>
+ {
let region = self.delegate.replace_region(br);
- if let RegionKind::ReBound(debruijn1, br) = region.kind() {
+ if let RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn1), br) = region.kind()
+ {
// If the callback returns a bound region,
// that region should always use the INNERMOST
// debruijn index. Then we adjust it to the
@@ -116,7 +120,9 @@
fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
match ct.kind() {
- ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+ ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_const)
+ if debruijn == self.current_index =>
+ {
let ct = self.delegate.replace_const(bound_const);
debug_assert!(!ct.has_vars_bound_above(DebruijnIndex::ZERO));
rustc_type_ir::shift_vars(self.interner, ct, self.current_index.as_u32())
diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs
index 262da85..7783075 100644
--- a/crates/hir-ty/src/next_solver/fulfill.rs
+++ b/crates/hir-ty/src/next_solver/fulfill.rs
@@ -2,7 +2,7 @@
mod errors;
-use std::{marker::PhantomData, mem, ops::ControlFlow, vec::ExtractIf};
+use std::{mem, ops::ControlFlow};
use rustc_hash::FxHashSet;
use rustc_next_trait_solver::{
@@ -46,6 +46,7 @@
/// outside of this snapshot leads to subtle bugs if the snapshot
/// gets rolled back. Because of this we explicitly check that we only
/// use the context in exactly this snapshot.
+ #[expect(unused)]
usable_in_snapshot: usize,
}
@@ -69,10 +70,6 @@
self.pending.push((obligation, stalled_on));
}
- fn has_pending_obligations(&self) -> bool {
- !self.pending.is_empty() || !self.overflowed.is_empty()
- }
-
fn clone_pending(&self) -> PredicateObligations<'db> {
let mut obligations: PredicateObligations<'db> =
self.pending.iter().map(|(o, _)| o.clone()).collect();
@@ -125,10 +122,10 @@
}
impl<'db> FulfillmentCtxt<'db> {
- #[tracing::instrument(level = "trace", skip(self, infcx))]
+ #[tracing::instrument(level = "trace", skip(self, _infcx))]
pub(crate) fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'db>,
+ _infcx: &InferCtxt<'db>,
obligation: PredicateObligation<'db>,
) {
// FIXME: See the comment in `try_evaluate_obligations()`.
@@ -138,7 +135,7 @@
pub(crate) fn register_predicate_obligations(
&mut self,
- infcx: &InferCtxt<'db>,
+ _infcx: &InferCtxt<'db>,
obligations: impl IntoIterator<Item = PredicateObligation<'db>>,
) {
// FIXME: See the comment in `try_evaluate_obligations()`.
@@ -148,7 +145,7 @@
pub(crate) fn collect_remaining_errors(
&mut self,
- infcx: &InferCtxt<'db>,
+ _infcx: &InferCtxt<'db>,
) -> Vec<NextSolverError<'db>> {
self.obligations
.pending
@@ -235,10 +232,6 @@
self.collect_remaining_errors(infcx)
}
- fn has_pending_obligations(&self) -> bool {
- self.obligations.has_pending_obligations()
- }
-
pub(crate) fn pending_obligations(&self) -> PredicateObligations<'db> {
self.obligations.clone_pending()
}
diff --git a/crates/hir-ty/src/next_solver/fulfill/errors.rs b/crates/hir-ty/src/next_solver/fulfill/errors.rs
index ab4a229..82dbf94 100644
--- a/crates/hir-ty/src/next_solver/fulfill/errors.rs
+++ b/crates/hir-ty/src/next_solver/fulfill/errors.rs
@@ -9,15 +9,15 @@
use rustc_type_ir::{
AliasRelationDirection, AliasTermKind, HostEffectPredicate, Interner, PredicatePolarity,
error::ExpectedFound,
- inherent::{IntoKind, PlaceholderConst, SliceLike, Span as _},
+ inherent::{IntoKind, SliceLike, Span as _},
lang_items::SolverTraitLangItem,
- solve::{CandidateSource, Certainty, GoalSource, MaybeCause, NoSolution},
+ solve::{Certainty, GoalSource, MaybeCause, NoSolution},
};
use tracing::{instrument, trace};
use crate::next_solver::{
AliasTerm, Binder, ClauseKind, Const, ConstKind, DbInterner, PolyTraitPredicate, PredicateKind,
- SolverContext, SolverDefId, Span, Term, TraitPredicate, Ty, TyKind, TypeError,
+ SolverContext, Span, Term, TraitPredicate, Ty, TyKind, TypeError,
fulfill::NextSolverError,
infer::{
InferCtxt,
@@ -529,7 +529,6 @@
}
}
- let mut impl_where_bound_count = 0;
for nested_goal in nested_goals {
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
@@ -542,34 +541,27 @@
recursion_depth: self.obligation.recursion_depth + 1,
};
- let obligation;
- match (child_mode, nested_goal.source()) {
+ let obligation = match (child_mode, nested_goal.source()) {
(
ChildMode::Trait(_) | ChildMode::Host(_),
GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
) => {
continue;
}
- (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
- obligation = make_obligation();
- impl_where_bound_count += 1;
+ (ChildMode::Trait(_parent_trait_pred), GoalSource::ImplWhereBound) => {
+ make_obligation()
}
(
- ChildMode::Host(parent_host_pred),
+ ChildMode::Host(_parent_host_pred),
GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
- ) => {
- obligation = make_obligation();
- impl_where_bound_count += 1;
- }
+ ) => make_obligation(),
// Skip over a higher-ranked predicate.
- (_, GoalSource::InstantiateHigherRanked) => {
- obligation = self.obligation.clone();
- }
+ (_, GoalSource::InstantiateHigherRanked) => self.obligation.clone(),
(ChildMode::PassThrough, _)
| (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
- obligation = make_obligation();
+ make_obligation()
}
- }
+ };
self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
}
@@ -628,35 +620,29 @@
}
mod wf {
- use std::iter;
-
use hir_def::ItemContainerId;
use rustc_type_ir::inherent::{
- AdtDef, BoundExistentialPredicates, GenericArg, GenericArgs as _, IntoKind, SliceLike,
- Term as _, Ty as _,
+ AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _,
+ Ty as _,
};
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::{
- Interner, PredicatePolarity, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
- TypeVisitor,
+ Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
- use tracing::{debug, instrument, trace};
+ use tracing::{debug, instrument};
use crate::next_solver::infer::InferCtxt;
- use crate::next_solver::infer::traits::{
- Obligation, ObligationCause, PredicateObligation, PredicateObligations,
- };
+ use crate::next_solver::infer::traits::{Obligation, ObligationCause, PredicateObligations};
use crate::next_solver::{
- AliasTerm, Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate,
- GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitPredicate,
- TraitRef, Ty, TyKind,
+ Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, GenericArgs,
+ ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind,
};
/// Compute the predicates that are required for a type to be well-formed.
///
/// This is only intended to be used in the new solver, since it does not
/// take into account recursion depth or proper error-reporting spans.
- pub fn unnormalized_obligations<'db>(
+ pub(crate) fn unnormalized_obligations<'db>(
infcx: &InferCtxt<'db>,
param_env: ParamEnv<'db>,
term: Term<'db>,
@@ -683,158 +669,11 @@
recursion_depth: usize,
}
- /// Controls whether we "elaborate" supertraits and so forth on the WF
- /// predicates. This is a kind of hack to address #43784. The
- /// underlying problem in that issue was a trait structure like:
- ///
- /// ```ignore (illustrative)
- /// trait Foo: Copy { }
- /// trait Bar: Foo { }
- /// impl<T: Bar> Foo for T { }
- /// impl<T> Bar for T { }
- /// ```
- ///
- /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
- /// we decide that this is true because `T: Bar` is in the
- /// where-clauses (and we can elaborate that to include `T:
- /// Copy`). This wouldn't be a problem, except that when we check the
- /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
- /// impl. And so nowhere did we check that `T: Copy` holds!
- ///
- /// To resolve this, we elaborate the WF requirements that must be
- /// proven when checking impls. This means that (e.g.) the `impl Bar
- /// for T` will be forced to prove not only that `T: Foo` but also `T:
- /// Copy` (which it won't be able to do, because there is no `Copy`
- /// impl for `T`).
- #[derive(Debug, PartialEq, Eq, Copy, Clone)]
- enum Elaborate {
- All,
- None,
- }
-
impl<'a, 'db> WfPredicates<'a, 'db> {
fn interner(&self) -> DbInterner<'db> {
self.infcx.interner
}
- /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
- fn add_wf_preds_for_trait_pred(
- &mut self,
- trait_pred: TraitPredicate<'db>,
- elaborate: Elaborate,
- ) {
- let tcx = self.interner();
- let trait_ref = trait_pred.trait_ref;
-
- // Negative trait predicates don't require supertraits to hold, just
- // that their args are WF.
- if trait_pred.polarity == PredicatePolarity::Negative {
- self.add_wf_preds_for_negative_trait_pred(trait_ref);
- return;
- }
-
- // if the trait predicate is not const, the wf obligations should not be const as well.
- let obligations = self.nominal_obligations(trait_ref.def_id.0.into(), trait_ref.args);
-
- debug!("compute_trait_pred obligations {:?}", obligations);
- let param_env = self.param_env;
- let depth = self.recursion_depth;
-
- let extend = |PredicateObligation { predicate, mut cause, .. }| {
- Obligation::with_depth(tcx, cause, depth, param_env, predicate)
- };
-
- if let Elaborate::All = elaborate {
- let implied_obligations = rustc_type_ir::elaborate::elaborate(tcx, obligations);
- let implied_obligations = implied_obligations.map(extend);
- self.out.extend(implied_obligations);
- } else {
- self.out.extend(obligations);
- }
-
- self.out.extend(
- trait_ref
- .args
- .iter()
- .enumerate()
- .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t)))
- .filter(|(_, term)| !term.has_escaping_bound_vars())
- .map(|(i, term)| {
- let mut cause = ObligationCause::misc();
- // The first arg is the self ty - use the correct span for it.
- Obligation::with_depth(
- tcx,
- cause,
- depth,
- param_env,
- ClauseKind::WellFormed(term),
- )
- }),
- );
- }
-
- // Compute the obligations that are required for `trait_ref` to be WF,
- // given that it is a *negative* trait predicate.
- fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: TraitRef<'db>) {
- for arg in trait_ref.args {
- if let Some(term) = arg.as_term() {
- self.add_wf_preds_for_term(term);
- }
- }
- }
-
- /// Pushes the obligations required for an alias (except inherent) to be WF
- /// into `self.out`.
- fn add_wf_preds_for_alias_term(&mut self, data: AliasTerm<'db>) {
- // A projection is well-formed if
- //
- // (a) its predicates hold (*)
- // (b) its args are wf
- //
- // (*) The predicates of an associated type include the predicates of
- // the trait that it's contained in. For example, given
- //
- // trait A<T>: Clone {
- // type X where T: Copy;
- // }
- //
- // The predicates of `<() as A<i32>>::X` are:
- // [
- // `(): Sized`
- // `(): Clone`
- // `(): A<i32>`
- // `i32: Sized`
- // `i32: Clone`
- // `i32: Copy`
- // ]
- let obligations = self.nominal_obligations(data.def_id, data.args);
- self.out.extend(obligations);
-
- self.add_wf_preds_for_projection_args(data.args);
- }
-
- fn add_wf_preds_for_projection_args(&mut self, args: GenericArgs<'db>) {
- let tcx = self.interner();
- let cause = ObligationCause::new();
- let param_env = self.param_env;
- let depth = self.recursion_depth;
-
- self.out.extend(
- args.iter()
- .filter_map(|arg| arg.as_term())
- .filter(|term| !term.has_escaping_bound_vars())
- .map(|term| {
- Obligation::with_depth(
- tcx,
- cause.clone(),
- depth,
- param_env,
- ClauseKind::WellFormed(term),
- )
- }),
- );
- }
-
fn require_sized(&mut self, subty: Ty<'db>) {
if !subty.has_escaping_bound_vars() {
let cause = ObligationCause::new();
@@ -895,7 +734,7 @@
fn add_wf_preds_for_dyn_ty(
&mut self,
- ty: Ty<'db>,
+ _ty: Ty<'db>,
data: &[Binder<'db, ExistentialPredicate<'db>>],
region: Region<'db>,
) {
@@ -1013,7 +852,7 @@
));
}
- TyKind::Pat(base_ty, pat) => {
+ TyKind::Pat(base_ty, _pat) => {
self.require_sized(base_ty);
}
@@ -1036,7 +875,7 @@
let obligations = self.nominal_obligations(data.def_id, data.args);
self.out.extend(obligations);
}
- TyKind::Alias(rustc_type_ir::Inherent, data) => {
+ TyKind::Alias(rustc_type_ir::Inherent, _data) => {
return;
}
@@ -1148,7 +987,7 @@
// Let the visitor iterate into the argument/return
// types appearing in the fn signature.
}
- TyKind::UnsafeBinder(ty) => {}
+ TyKind::UnsafeBinder(_ty) => {}
TyKind::Dynamic(data, r) => {
// WfObject
@@ -1291,7 +1130,7 @@
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
- pub fn object_region_bounds<'db>(
+ pub(crate) fn object_region_bounds<'db>(
interner: DbInterner<'db>,
existential_predicates: &[Binder<'db, ExistentialPredicate<'db>>],
) -> Vec<Region<'db>> {
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 38293c4..90bd44a 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -1,27 +1,20 @@
//! Things related to generic args in the next-trait-solver.
use hir_def::{GenericDefId, GenericParamId};
-use intern::{Interned, Symbol};
use macros::{TypeFoldable, TypeVisitable};
-use rustc_type_ir::inherent::Const as _;
use rustc_type_ir::{
- ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys,
- GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable,
- Variance,
- inherent::{
- GenericArg as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _,
- },
+ ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSigTys,
+ GenericArgKind, Interner, TermKind, TyKind, TyVid, Variance,
+ inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _},
relate::{Relate, VarianceDiagInfo},
};
use smallvec::SmallVec;
-use crate::db::HirDatabase;
-use crate::next_solver::{Binder, PolyFnSig};
+use crate::next_solver::{PolyFnSig, interned_vec_db};
use super::{
Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys,
- generics::{GenericParamDef, Generics},
- interned_vec_db,
+ generics::Generics,
};
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
@@ -191,7 +184,7 @@
mut mk_kind: F,
) -> GenericArgs<'db>
where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
let defs = interner.generics_of(def_id);
let count = defs.count();
@@ -202,9 +195,7 @@
/// Creates an all-error `GenericArgs`.
pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> {
- GenericArgs::for_item(interner, def_id, |_, _, id, _| {
- GenericArg::error_from_id(interner, id)
- })
+ GenericArgs::for_item(interner, def_id, |_, id, _| GenericArg::error_from_id(interner, id))
}
/// Like `for_item`, but prefers the default of a parameter if it has any.
@@ -214,14 +205,12 @@
mut fallback: F,
) -> GenericArgs<'db>
where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
- let defaults = interner.db.generic_defaults_ns(def_id);
- Self::for_item(interner, def_id.into(), |name, idx, id, prev| {
- match defaults.get(idx as usize) {
- Some(default) => default.instantiate(interner, prev),
- None => fallback(name, idx, id, prev),
- }
+ let defaults = interner.db.generic_defaults(def_id);
+ Self::for_item(interner, def_id.into(), |idx, id, prev| match defaults.get(idx as usize) {
+ Some(default) => default.instantiate(interner, prev),
+ None => fallback(idx, id, prev),
})
}
@@ -233,11 +222,11 @@
mut fallback: F,
) -> GenericArgs<'db>
where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
let mut iter = first.into_iter();
- Self::for_item(interner, def_id, |name, idx, id, prev| {
- iter.next().unwrap_or_else(|| fallback(name, idx, id, prev))
+ Self::for_item(interner, def_id, |idx, id, prev| {
+ iter.next().unwrap_or_else(|| fallback(idx, id, prev))
})
}
@@ -249,14 +238,14 @@
mut fallback: F,
) -> GenericArgs<'db>
where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
- let defaults = interner.db.generic_defaults_ns(def_id);
- Self::fill_rest(interner, def_id.into(), first, |name, idx, id, prev| {
+ let defaults = interner.db.generic_defaults(def_id);
+ Self::fill_rest(interner, def_id.into(), first, |idx, id, prev| {
defaults
.get(idx as usize)
.map(|default| default.instantiate(interner, prev))
- .unwrap_or_else(|| fallback(name, idx, id, prev))
+ .unwrap_or_else(|| fallback(idx, id, prev))
})
}
@@ -266,9 +255,8 @@
defs: Generics,
mk_kind: &mut F,
) where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
- let self_len = defs.own_params.len() as u32;
if let Some(def_id) = defs.parent {
let parent_defs = interner.generics_of(def_id.into());
Self::fill_item(args, interner, parent_defs, mk_kind);
@@ -278,12 +266,11 @@
fn fill_single<F>(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F)
where
- F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
{
- let start_len = args.len();
args.reserve(defs.own_params.len());
for param in &defs.own_params {
- let kind = mk_kind(¶m.name, args.len() as u32, param.id, args);
+ let kind = mk_kind(args.len() as u32, param.id, args);
args.push(kind);
}
}
@@ -374,9 +361,7 @@
interner: DbInterner<'db>,
def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
- Self::for_item(interner, def_id, |name, index, kind, _| {
- mk_param(interner, index, name, kind)
- })
+ Self::for_item(interner, def_id, |index, kind, _| mk_param(interner, index, kind))
}
fn extend_with_error(
@@ -384,7 +369,7 @@
def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
original_args: &[<DbInterner<'db> as rustc_type_ir::Interner>::GenericArg],
) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
- Self::for_item(interner, def_id, |name, index, kind, _| {
+ Self::for_item(interner, def_id, |index, kind, _| {
if let Some(arg) = original_args.get(index as usize) {
*arg
} else {
@@ -461,7 +446,6 @@
signature_parts_ty,
tupled_upvars_ty,
coroutine_captures_by_ref_ty,
- coroutine_witness_ty,
] => rustc_type_ir::CoroutineClosureArgsParts {
parent_args: GenericArgs::new_from_iter(
DbInterner::conjure(),
@@ -494,18 +478,12 @@
}
}
-pub fn mk_param<'db>(
- interner: DbInterner<'db>,
- index: u32,
- name: &Symbol,
- id: GenericParamId,
-) -> GenericArg<'db> {
- let name = name.clone();
+pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> {
match id {
GenericParamId::LifetimeParamId(id) => {
Region::new_early_param(interner, EarlyParamRegion { index, id }).into()
}
- GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index, name).into(),
+ GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index).into(),
GenericParamId::ConstParamId(id) => {
Const::new_param(interner, ParamConst { index, id }).into()
}
@@ -596,13 +574,4 @@
{
T::collect_and_apply(iter, |xs| self.mk_args(xs))
}
-
- pub(super) fn check_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) -> bool {
- // TODO
- true
- }
-
- pub(super) fn debug_assert_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) {
- // TODO
- }
}
diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs
index 5ec9a18..4d164a7 100644
--- a/crates/hir-ty/src/next_solver/generics.rs
+++ b/crates/hir-ty/src/next_solver/generics.rs
@@ -1,36 +1,22 @@
//! Things related to generics in the next-trait-solver.
use hir_def::{
- ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
- TypeOrConstParamId, TypeParamId,
- db::DefDatabase,
- expr_store::ExpressionStore,
- hir::generics::{
- GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId,
- LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
- WherePredicate,
- },
+ ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
+ hir::generics::{GenericParams, TypeOrConstParamData},
};
-use hir_expand::name::Name;
-use intern::{Symbol, sym};
-use la_arena::Arena;
-use rustc_type_ir::inherent::Ty as _;
-use triomphe::Arc;
-use crate::{db::HirDatabase, generics::parent_generic_def, next_solver::Ty};
+use crate::{db::HirDatabase, generics::parent_generic_def};
-use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId};
+use super::SolverDefId;
-use super::{DbInterner, GenericArg};
+use super::DbInterner;
pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
- let mk_lt = |parent, index, local_id, lt: &LifetimeParamData| {
- let name = lt.name.symbol().clone();
+ let mk_lt = |parent, index, local_id| {
let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
- GenericParamDef { name, index, id }
+ GenericParamDef { index, id }
};
let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| {
- let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME);
let id = TypeOrConstParamId { parent, local_id };
let id = match p {
TypeOrConstParamData::TypeParamData(_) => {
@@ -40,7 +26,7 @@
GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
}
};
- GenericParamDef { name, index, id }
+ GenericParamDef { index, id }
};
let own_params_for_generic_params = |parent, params: &GenericParams| {
let mut result = Vec::with_capacity(params.len());
@@ -51,8 +37,8 @@
type_and_consts.next();
index += 1;
}
- result.extend(params.iter_lt().map(|(local_id, data)| {
- let lt = mk_lt(parent, index, local_id, data);
+ result.extend(params.iter_lt().map(|(local_id, _data)| {
+ let lt = mk_lt(parent, index, local_id);
index += 1;
lt
}));
@@ -78,27 +64,6 @@
crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
(Some(type_alias_id.into()), Vec::new())
}
- crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
- let param = TypeOrConstParamData::TypeParamData(TypeParamData {
- name: None,
- default: None,
- provenance: TypeParamProvenance::TypeParamList,
- });
- // Yes, there is a parent but we don't include it in the generics
- // FIXME: It seems utterly sensitive to fake a generic param here.
- // Also, what a horrible mess!
- (
- None,
- vec![mk_ty(
- GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe {
- salsa::Id::from_index(salsa::Id::MAX_U32 - 1)
- })),
- 0,
- LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
- ¶m,
- )],
- )
- }
}
}
_ => panic!("No generics for {def:?}"),
@@ -121,8 +86,6 @@
#[derive(Debug)]
pub struct GenericParamDef {
- pub(crate) name: Symbol,
- //def_id: GenericDefId,
index: u32,
pub(crate) id: GenericParamId,
}
diff --git a/crates/hir-ty/src/next_solver/infer/at.rs b/crates/hir-ty/src/next_solver/infer/at.rs
index 8dfffe0..70b6594 100644
--- a/crates/hir-ty/src/next_solver/infer/at.rs
+++ b/crates/hir-ty/src/next_solver/infer/at.rs
@@ -36,7 +36,7 @@
AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv,
PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term,
TraitRef, Ty,
- fulfill::{FulfillmentCtxt, NextSolverError},
+ fulfill::NextSolverError,
infer::relate::lattice::{LatticeOp, LatticeOpKind},
};
@@ -45,16 +45,6 @@
traits::{Obligation, ObligationCause},
};
-/// Whether we should define opaque types or just treat them opaquely.
-///
-/// Currently only used to prevent predicate matching from matching anything
-/// against opaque types.
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum DefineOpaqueTypes {
- Yes,
- No,
-}
-
#[derive(Clone, Copy)]
pub struct At<'a, 'db> {
pub infcx: &'a InferCtxt<'db>,
@@ -107,12 +97,7 @@
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
/// `sup(i32, x)`, since the "expected" type is the type that
/// appears in the signature.
- pub fn sup<T>(
- self,
- define_opaque_types: DefineOpaqueTypes,
- expected: T,
- actual: T,
- ) -> InferResult<'db, ()>
+ pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
where
T: ToTrace<'db>,
{
@@ -128,12 +113,7 @@
}
/// Makes `expected <: actual`.
- pub fn sub<T>(
- self,
- define_opaque_types: DefineOpaqueTypes,
- expected: T,
- actual: T,
- ) -> InferResult<'db, ()>
+ pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
where
T: ToTrace<'db>,
{
@@ -149,31 +129,7 @@
}
/// Makes `expected == actual`.
- pub fn eq<T>(
- self,
- define_opaque_types: DefineOpaqueTypes,
- expected: T,
- actual: T,
- ) -> InferResult<'db, ()>
- where
- T: ToTrace<'db>,
- {
- self.eq_trace(
- define_opaque_types,
- ToTrace::to_trace(self.cause, expected, actual),
- expected,
- actual,
- )
- }
-
- /// Makes `expected == actual`.
- pub fn eq_trace<T>(
- self,
- define_opaque_types: DefineOpaqueTypes,
- trace: TypeTrace<'db>,
- expected: T,
- actual: T,
- ) -> InferResult<'db, ()>
+ pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
where
T: Relate<DbInterner<'db>>,
{
@@ -188,20 +144,14 @@
.map(|goals| self.goals_to_obligations(goals))
}
- pub fn relate<T>(
- self,
- define_opaque_types: DefineOpaqueTypes,
- expected: T,
- variance: Variance,
- actual: T,
- ) -> InferResult<'db, ()>
+ pub fn relate<T>(self, expected: T, variance: Variance, actual: T) -> InferResult<'db, ()>
where
T: ToTrace<'db>,
{
match variance {
- Variance::Covariant => self.sub(define_opaque_types, expected, actual),
- Variance::Invariant => self.eq(define_opaque_types, expected, actual),
- Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
+ Variance::Covariant => self.sub(expected, actual),
+ Variance::Invariant => self.eq(expected, actual),
+ Variance::Contravariant => self.sup(expected, actual),
// We could make this make sense but it's not readily
// exposed and I don't feel like dealing with it. Note
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
index beaac11..7995545 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
@@ -10,17 +10,16 @@
use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar};
use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _};
use rustc_type_ir::{
- BoundVar, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind, TyVid, TypeFlags,
- TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
+ BoundVar, BoundVarIndexKind, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind,
+ TyVid, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
};
use smallvec::SmallVec;
use tracing::debug;
use crate::next_solver::infer::InferCtxt;
use crate::next_solver::{
- Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind,
- CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty,
- TyKind,
+ Binder, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg,
+ ParamEnvAnd, Placeholder, Region, Ty, TyKind,
};
/// When we canonicalize a value to form a query, we wind up replacing
@@ -345,12 +344,9 @@
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
match r.kind() {
- RegionKind::ReBound(index, ..) => {
- if index >= self.binder_index {
- panic!("escaping late-bound region during canonicalization");
- } else {
- r
- }
+ RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => r,
+ RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
+ panic!("canonicalized bound var found during canonicalization");
}
RegionKind::ReStatic
@@ -427,12 +423,9 @@
self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
}
- TyKind::Bound(debruijn, _) => {
- if debruijn >= self.binder_index {
- panic!("escaping bound type during canonicalization")
- } else {
- t
- }
+ TyKind::Bound(BoundVarIndexKind::Bound(..), _) => t,
+ TyKind::Bound(BoundVarIndexKind::Canonical, ..) => {
+ panic!("canonicalized bound var found during canonicalization");
}
TyKind::Closure(..)
@@ -503,12 +496,11 @@
ConstKind::Infer(InferConst::Fresh(_)) => {
panic!("encountered a fresh const during canonicalization")
}
- ConstKind::Bound(debruijn, _) => {
- if debruijn >= self.binder_index {
- panic!("escaping bound const during canonicalization")
- } else {
- return ct;
- }
+ ConstKind::Bound(BoundVarIndexKind::Bound(..), _) => {
+ return ct;
+ }
+ ConstKind::Bound(BoundVarIndexKind::Canonical, ..) => {
+ panic!("canonicalized bound var found during canonicalization");
}
ConstKind::Placeholder(placeholder) => {
return self
@@ -758,8 +750,7 @@
r: Region<'db>,
) -> Region<'db> {
let var = self.canonical_var(info, r.into());
- let br = BoundRegion { var, kind: BoundRegionKind::Anon };
- Region::new_bound(self.cx(), self.binder_index, br)
+ Region::new_canonical_bound(self.cx(), var)
}
/// Given a type variable `ty_var` of the given kind, first check
@@ -769,11 +760,7 @@
fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> {
debug_assert_eq!(ty_var, self.infcx.shallow_resolve(ty_var));
let var = self.canonical_var(info, ty_var.into());
- Ty::new_bound(
- self.tcx,
- self.binder_index,
- BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var },
- )
+ Ty::new_canonical_bound(self.cx(), var)
}
/// Given a type variable `const_var` of the given kind, first check
@@ -787,6 +774,6 @@
) -> Const<'db> {
debug_assert_eq!(const_var, self.infcx.shallow_resolve_const(const_var));
let var = self.canonical_var(info, const_var.into());
- Const::new_bound(self.tcx, self.binder_index, BoundConst { var })
+ Const::new_canonical_bound(self.cx(), var)
}
}
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
index 6c7a87e..6360291 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
@@ -6,24 +6,15 @@
//!
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
-use crate::next_solver::BoundConst;
use crate::next_solver::{
- AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal,
- ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind,
- fold::FnMutDelegate,
- infer::{
- DefineOpaqueTypes, InferCtxt, TypeTrace,
- traits::{Obligation, PredicateObligations},
- },
+ BoundConst, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Clauses, Const, ConstKind,
+ DbInterner, GenericArg, Predicate, Region, RegionKind, Ty, TyKind, fold::FnMutDelegate,
};
+use rustc_hash::FxHashMap;
use rustc_type_ir::{
- AliasRelationDirection, AliasTyKind, BoundVar, GenericArgKind, InferTy, TypeFoldable, Upcast,
- Variance,
- inherent::{IntoKind, SliceLike},
- relate::{
- Relate, TypeRelation, VarianceDiagInfo,
- combine::{super_combine_consts, super_combine_tys},
- },
+ BoundVarIndexKind, GenericArgKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitableExt,
+ inherent::{GenericArg as _, IntoKind, SliceLike},
};
pub trait CanonicalExt<'db, V> {
@@ -102,6 +93,79 @@
},
};
- tcx.replace_escaping_bound_vars_uncached(value, delegate)
+ let value = tcx.replace_escaping_bound_vars_uncached(value, delegate);
+ value.fold_with(&mut CanonicalInstantiator {
+ tcx,
+ var_values: var_values.var_values.as_slice(),
+ cache: Default::default(),
+ })
+ }
+}
+
+/// Replaces the bound vars in a canonical binder with var values.
+struct CanonicalInstantiator<'db, 'a> {
+ tcx: DbInterner<'db>,
+
+ // The values that the bound vars are being instantiated with.
+ var_values: &'a [GenericArg<'db>],
+
+ // Because we use `BoundVarIndexKind::Canonical`, we can cache
+ // based only on the entire ty, not worrying about a `DebruijnIndex`
+ cache: FxHashMap<Ty<'db>, Ty<'db>>,
+}
+
+impl<'db, 'a> TypeFolder<DbInterner<'db>> for CanonicalInstantiator<'db, 'a> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
+ match t.kind() {
+ TyKind::Bound(BoundVarIndexKind::Canonical, bound_ty) => {
+ self.var_values[bound_ty.var.as_usize()].expect_ty()
+ }
+ _ => {
+ if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
+ t
+ } else if let Some(&t) = self.cache.get(&t) {
+ t
+ } else {
+ let res = t.super_fold_with(self);
+ assert!(self.cache.insert(t, res).is_none());
+ res
+ }
+ }
+ }
+ }
+
+ fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+ match r.kind() {
+ RegionKind::ReBound(BoundVarIndexKind::Canonical, br) => {
+ self.var_values[br.var.as_usize()].expect_region()
+ }
+ _ => r,
+ }
+ }
+
+ fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+ match ct.kind() {
+ ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
+ self.var_values[bound_const.var.as_usize()].expect_const()
+ }
+ _ => ct.super_fold_with(self),
+ }
+ }
+
+ fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
+ if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
+ }
+
+ fn fold_clauses(&mut self, c: Clauses<'db>) -> Clauses<'db> {
+ if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
+ return c;
+ }
+
+ // FIXME: We might need cache here for perf like rustc
+ c.super_fold_with(self)
}
}
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
index d0669f5..b3bd0a4 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
@@ -22,26 +22,13 @@
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
use crate::next_solver::{
- AliasTy, Binder, Canonical, CanonicalVarValues, CanonicalVars, Const, DbInterner, GenericArg,
- Goal, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind,
- Region, Ty, TyKind,
- infer::{
- DefineOpaqueTypes, InferCtxt, TypeTrace,
- traits::{Obligation, PredicateObligations},
- },
+ Canonical, CanonicalVarValues, Const, DbInterner, GenericArg, PlaceholderConst,
+ PlaceholderRegion, PlaceholderTy, Region, Ty, TyKind, infer::InferCtxt,
};
use instantiate::CanonicalExt;
use rustc_index::IndexVec;
use rustc_type_ir::inherent::IntoKind;
-use rustc_type_ir::{
- AliasRelationDirection, AliasTyKind, CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex,
- Upcast, Variance,
- inherent::{SliceLike, Ty as _},
- relate::{
- Relate, TypeRelation, VarianceDiagInfo,
- combine::{super_combine_consts, super_combine_tys},
- },
-};
+use rustc_type_ir::{CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, inherent::Ty as _};
pub mod canonicalizer;
pub mod instantiate;
diff --git a/crates/hir-ty/src/next_solver/infer/context.rs b/crates/hir-ty/src/next_solver/infer/context.rs
index 5aa5ad1..397986e 100644
--- a/crates/hir-ty/src/next_solver/infer/context.rs
+++ b/crates/hir-ty/src/next_solver/infer/context.rs
@@ -1,19 +1,19 @@
//! Definition of `InferCtxtLike` from the librarified type layer.
use rustc_type_ir::{
- ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntTy, IntVarValue,
- IntVid, RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex,
- inherent::{Const as _, IntoKind, Span as _, Ty as _},
+ ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntVarValue, IntVid,
+ RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex,
+ inherent::{Const as _, IntoKind, Ty as _},
relate::combine::PredicateEmittingRelation,
};
use crate::next_solver::{
- Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, ParamEnv,
- Region, SolverDefId, Span, Ty, TyKind,
+ Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region,
+ SolverDefId, Span, Ty, TyKind,
infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries},
};
-use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult, traits::ObligationCause};
+use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult};
impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> {
type Interner = DbInterner<'db>;
@@ -250,16 +250,16 @@
self.probe(|_| probe())
}
- fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, span: Span) {
+ fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, _span: Span) {
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(sub, sup);
}
- fn equate_regions(&self, a: Region<'db>, b: Region<'db>, span: Span) {
+ fn equate_regions(&self, a: Region<'db>, b: Region<'db>, _span: Span) {
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(a, b);
}
- fn register_ty_outlives(&self, ty: Ty<'db>, r: Region<'db>, span: Span) {
- //self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(Span::dummy()));
+ fn register_ty_outlives(&self, _ty: Ty<'db>, _r: Region<'db>, _span: Span) {
+ // self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy());
}
type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries;
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index e1a46fa..36c6c48 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -6,32 +6,23 @@
use std::sync::Arc;
pub use BoundRegionConversionTime::*;
-pub use at::DefineOpaqueTypes;
-use ena::undo_log::UndoLogs;
use ena::unify as ut;
use hir_def::GenericParamId;
use hir_def::lang_item::LangItem;
-use intern::Symbol;
use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage};
-use region_constraints::{
- GenericKind, RegionConstraintCollector, RegionConstraintStorage, UndoLog, VarInfos, VerifyBound,
-};
-pub use relate::StructurallyRelateAliases;
-pub use relate::combine::PredicateEmittingRelation;
-use rustc_hash::{FxHashMap, FxHashSet};
+use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
use rustc_pattern_analysis::Captures;
+use rustc_type_ir::TypeFoldable;
use rustc_type_ir::error::{ExpectedFound, TypeError};
use rustc_type_ir::inherent::{
- Const as _, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Term as _,
- Ty as _,
+ Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _,
};
use rustc_type_ir::{
- BoundVar, ClosureKind, ConstVid, FloatTy, FloatVarValue, FloatVid, GenericArgKind, InferConst,
- InferTy, IntTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
+ ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy,
+ IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
};
use rustc_type_ir::{TermKind, TypeVisitableExt};
-use rustc_type_ir::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use snapshot::undo_log::InferCtxtUndoLogs;
use tracing::{debug, instrument};
use traits::{ObligationCause, PredicateObligations};
@@ -39,19 +30,17 @@
use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use crate::next_solver::fold::BoundVarReplacerDelegate;
-use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries;
use crate::next_solver::infer::select::EvaluationResult;
use crate::next_solver::infer::traits::PredicateObligation;
use crate::next_solver::obligation_ctxt::ObligationCtxt;
use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext};
-use super::generics::GenericParamDef;
use super::{
- AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind,
- DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv,
- PlaceholderRegion, PolyCoercePredicate, PolyExistentialProjection, PolyExistentialTraitRef,
- PolyFnSig, PolyRegionOutlivesPredicate, PolySubtypePredicate, Predicate, Region, SolverDefId,
- SubtypePredicate, Term, TraitPredicate, TraitRef, Ty, TyKind, TypingMode,
+ AliasTerm, Binder, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner,
+ ErrorGuaranteed, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, PolyCoercePredicate,
+ PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyRegionOutlivesPredicate,
+ PolySubtypePredicate, Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, TyKind,
+ TypingMode,
};
pub mod at;
@@ -82,8 +71,6 @@
}
pub type InferResult<'db, T> = Result<InferOk<'db, T>, TypeError<DbInterner<'db>>>;
-pub(crate) type FixupResult<T> = Result<T, FixupError>; // "fixup result"
-
pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable<
ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'db>>,
>;
@@ -440,6 +427,7 @@
/// check::<&'_ T>();
/// }
/// ```
+ #[expect(dead_code, reason = "this is used in rustc")]
fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'db>,
@@ -452,14 +440,13 @@
/// not entirely accurate if inference variables are involved.
///
/// This version ignores all outlives constraints.
+ #[expect(dead_code, reason = "this is used in rustc")]
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool {
self.evaluate_obligation(obligation).must_apply_modulo_regions()
}
/// Evaluate a given predicate, capturing overflow and propagating it back.
fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult {
- let param_env = obligation.param_env;
-
self.probe(|snapshot| {
let mut ocx = ObligationCtxt::new(self);
ocx.register_obligation(obligation.clone());
@@ -583,16 +570,16 @@
self.enter_forall(predicate, |SubtypePredicate { a_is_expected, a, b }| {
if a_is_expected {
- Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
+ Ok(self.at(cause, param_env).sub(a, b))
} else {
- Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
+ Ok(self.at(cause, param_env).sup(b, a))
}
})
}
pub fn region_outlives_predicate(
&self,
- cause: &traits::ObligationCause,
+ _cause: &traits::ObligationCause,
predicate: PolyRegionOutlivesPredicate<'db>,
) {
self.enter_forall(predicate, |OutlivesPredicate(r_a, r_b)| {
@@ -632,7 +619,7 @@
}
pub fn next_const_var(&self) -> Const<'db> {
- self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None })
+ self.next_const_var_with_origin(ConstVariableOrigin {})
}
pub fn next_const_vid(&self) -> ConstVid {
@@ -640,7 +627,7 @@
.borrow_mut()
.const_unification_table()
.new_key(ConstVariableValue::Unknown {
- origin: ConstVariableOrigin { param_def_id: None },
+ origin: ConstVariableOrigin {},
universe: self.universe(),
})
.vid
@@ -657,7 +644,7 @@
}
pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> {
- let origin = ConstVariableOrigin { param_def_id: None };
+ let origin = ConstVariableOrigin {};
let vid = self
.inner
.borrow_mut()
@@ -738,7 +725,7 @@
self.next_region_var_in_universe(universe)
}
- fn var_for_def(&self, id: GenericParamId, name: &Symbol) -> GenericArg<'db> {
+ fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> {
match id {
GenericParamId::LifetimeParamId(_) => {
// Create a region inference variable for the given
@@ -763,7 +750,7 @@
Ty::new_var(self.interner, ty_var_id).into()
}
GenericParamId::ConstParamId(_) => {
- let origin = ConstVariableOrigin { param_def_id: None };
+ let origin = ConstVariableOrigin {};
let const_var_id = self
.inner
.borrow_mut()
@@ -778,9 +765,7 @@
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping
/// each type/region parameter to a fresh inference variable.
pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> {
- GenericArgs::for_item(self.interner, def_id, |name, index, kind, _| {
- self.var_for_def(kind, name)
- })
+ GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind))
}
/// Like `fresh_args_for_item()`, but first uses the args from `first`.
@@ -789,8 +774,8 @@
def_id: SolverDefId,
first: impl IntoIterator<Item = GenericArg<'db>>,
) -> GenericArgs<'db> {
- GenericArgs::fill_rest(self.interner, def_id, first, |name, index, kind, _| {
- self.var_for_def(kind, name)
+ GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| {
+ self.var_for_def(kind)
})
}
@@ -828,8 +813,8 @@
defining_opaque_types_and_generators.contains(&id.into())
}
TypingMode::Coherence | TypingMode::PostAnalysis => false,
- TypingMode::Borrowck { defining_opaque_types } => unimplemented!(),
- TypingMode::PostBorrowckAnalysis { defined_opaque_types } => unimplemented!(),
+ TypingMode::Borrowck { defining_opaque_types: _ } => unimplemented!(),
+ TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => unimplemented!(),
}
}
@@ -998,7 +983,7 @@
// use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>(
&self,
- lbrct: BoundRegionConversionTime,
+ _lbrct: BoundRegionConversionTime,
value: Binder<'db, T>,
) -> T
where
@@ -1014,7 +999,7 @@
for bound_var_kind in bound_vars {
let arg: GenericArg<'db> = match bound_var_kind {
BoundVarKind::Ty(_) => self.next_ty_var().into(),
- BoundVarKind::Region(br) => self.next_region_var().into(),
+ BoundVarKind::Region(_) => self.next_region_var().into(),
BoundVarKind::Const => self.next_const_var().into(),
};
args.push(arg);
@@ -1070,7 +1055,7 @@
#[inline]
pub fn is_ty_infer_var_definitely_unchanged<'a>(
&'a self,
- ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a) {
+ ) -> impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a {
// This hoists the borrow/release out of the loop body.
let inner = self.inner.try_borrow();
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
index 0f68ec8..06d9984 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
@@ -1,40 +1,10 @@
//! Things related to the infer context of the next-trait-solver.
-use std::sync::Arc;
-
-use tracing::{debug, instrument};
-
-use crate::next_solver::{
- Clause, ClauseKind, FxIndexMap, GenericArgs, OpaqueTypeKey, ProjectionPredicate, SolverDefId,
- TypingMode, util::BottomUpFolder,
-};
-
pub(crate) mod table;
pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
-use crate::next_solver::{
- AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal,
- ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind,
- fold::FnMutDelegate,
- infer::{
- DefineOpaqueTypes, InferCtxt, TypeTrace,
- traits::{Obligation, PredicateObligations},
- },
-};
-use rustc_type_ir::{
- AliasRelationDirection, AliasTyKind, BoundConstness, BoundVar, Flags, GenericArgKind, InferTy,
- Interner, RegionKind, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
- TypeVisitableExt, TypeVisitor, Upcast, Variance,
- error::{ExpectedFound, TypeError},
- inherent::{DefId, GenericArgs as _, IntoKind, SliceLike},
- relate::{
- Relate, TypeRelation, VarianceDiagInfo,
- combine::{super_combine_consts, super_combine_tys},
- },
-};
-
-use super::{InferOk, traits::ObligationCause};
+use crate::next_solver::{OpaqueTypeKey, Ty, infer::InferCtxt};
#[derive(Copy, Clone, Debug)]
pub struct OpaqueHiddenType<'db> {
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
index 8ab409d..0f8b238 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
@@ -54,7 +54,7 @@
assert!(entry.is_some());
}
- pub fn is_empty(&self) -> bool {
+ pub(crate) fn is_empty(&self) -> bool {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
opaque_types.is_empty() && duplicate_entries.is_empty()
}
@@ -66,14 +66,14 @@
std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
}
- pub fn num_entries(&self) -> OpaqueTypeStorageEntries {
+ pub(crate) fn num_entries(&self) -> OpaqueTypeStorageEntries {
OpaqueTypeStorageEntries {
opaque_types: self.opaque_types.len(),
duplicate_entries: self.duplicate_entries.len(),
}
}
- pub fn opaque_types_added_since(
+ pub(crate) fn opaque_types_added_since(
&self,
prev_entries: OpaqueTypeStorageEntries,
) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
@@ -89,7 +89,7 @@
///
/// Outside of canonicalization one should generally use `iter_opaque_types`
/// to also consider duplicate entries.
- pub fn iter_lookup_table(
+ pub(crate) fn iter_lookup_table(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
self.opaque_types.iter().map(|(k, v)| (*k, *v))
@@ -100,13 +100,13 @@
/// These have to considered when checking all opaque type uses but are e.g.
/// irrelevant for canonical inputs as nested queries never meaningfully
/// accesses them.
- pub fn iter_duplicate_entries(
+ pub(crate) fn iter_duplicate_entries(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
self.duplicate_entries.iter().copied()
}
- pub fn iter_opaque_types(
+ pub(crate) fn iter_opaque_types(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
@@ -144,7 +144,7 @@
impl<'a, 'db> OpaqueTypeTable<'a, 'db> {
#[instrument(skip(self), level = "debug")]
- pub fn register(
+ pub(crate) fn register(
&mut self,
key: OpaqueTypeKey<'db>,
hidden_type: OpaqueHiddenType<'db>,
@@ -159,7 +159,11 @@
None
}
- pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'db>, hidden_type: OpaqueHiddenType<'db>) {
+ pub(crate) fn add_duplicate(
+ &mut self,
+ key: OpaqueTypeKey<'db>,
+ hidden_type: OpaqueHiddenType<'db>,
+ ) {
self.storage.duplicate_entries.push((key, hidden_type));
self.undo_log.push(UndoLog::DuplicateOpaqueType);
}
diff --git a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
index 7f15a46..ae5930d 100644
--- a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
@@ -1,7 +1,6 @@
//! See `README.md`.
use std::ops::Range;
-use std::sync::Arc;
use std::{cmp, fmt, mem};
use ena::undo_log::{Rollback, UndoLogs};
@@ -18,9 +17,7 @@
use super::unify_key::RegionVidKey;
use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
use crate::next_solver::infer::unify_key::RegionVariableValue;
-use crate::next_solver::{
- AliasTy, Binder, DbInterner, OpaqueTypeKey, ParamTy, PlaceholderTy, Region, Ty,
-};
+use crate::next_solver::{AliasTy, Binder, DbInterner, ParamTy, PlaceholderTy, Region, Ty};
#[derive(Debug, Clone, Default)]
pub struct RegionConstraintStorage<'db> {
@@ -254,6 +251,7 @@
AddConstraint(usize),
/// We added the given `verify`.
+ #[expect(dead_code, reason = "this is used in rustc")]
AddVerify(usize),
/// We added a GLB/LUB "combination variable".
diff --git a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
index 7e2735d..d06984c 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
@@ -7,8 +7,8 @@
use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _};
use rustc_type_ir::relate::VarianceDiagInfo;
use rustc_type_ir::{
- AliasRelationDirection, AliasTyKind, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind,
- TermKind, TyVid, UniverseIndex, Variance,
+ AliasRelationDirection, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind, TermKind,
+ TyVid, UniverseIndex, Variance,
};
use rustc_type_ir::{Interner, TypeVisitable, TypeVisitableExt};
use tracing::{debug, instrument, warn};
@@ -21,9 +21,8 @@
use crate::next_solver::infer::{InferCtxt, relate};
use crate::next_solver::util::MaxUniverse;
use crate::next_solver::{
- AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind,
- ProjectionPredicate, Region, SolverDefId, Term, TermVid, Ty, TyKind, TypingMode,
- UnevaluatedConst,
+ AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind, Region,
+ SolverDefId, Term, TermVid, Ty, TyKind, TypingMode, UnevaluatedConst,
};
impl<'db> InferCtxt<'db> {
diff --git a/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
index 62028e0..c523751 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
@@ -2,13 +2,10 @@
//! the end of the file for details.
use rustc_type_ir::TypeFoldable;
-use rustc_type_ir::{BoundVar, UniverseIndex};
use tracing::{debug, instrument};
-use super::RelateResult;
use crate::next_solver::fold::FnMutDelegate;
use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::infer::snapshot::CombinedSnapshot;
use crate::next_solver::{
Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst,
PlaceholderRegion, PlaceholderTy, Region, Ty,
diff --git a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
index c7f771f..374895c 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
@@ -30,7 +30,7 @@
AliasTy, Binder, Const, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Region, Span, Ty,
TyKind,
infer::{
- DefineOpaqueTypes, InferCtxt, TypeTrace,
+ InferCtxt, TypeTrace,
relate::RelateResult,
traits::{Obligation, PredicateObligations},
},
@@ -92,10 +92,7 @@
match variance {
Variance::Invariant => {
self.obligations.extend(
- self.infcx
- .at(&self.trace.cause, self.param_env)
- .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)?
- .into_obligations(),
+ self.infcx.at(&self.trace.cause, self.param_env).eq(a, b)?.into_obligations(),
);
Ok(a)
}
@@ -213,12 +210,12 @@
let at = self.infcx.at(&self.trace.cause, self.param_env);
match self.kind {
LatticeOpKind::Glb => {
- self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations());
- self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations());
+ self.obligations.extend(at.sub(v, a)?.into_obligations());
+ self.obligations.extend(at.sub(v, b)?.into_obligations());
}
LatticeOpKind::Lub => {
- self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations());
- self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations());
+ self.obligations.extend(at.sub(a, v)?.into_obligations());
+ self.obligations.extend(at.sub(b, v)?.into_obligations());
}
}
Ok(())
diff --git a/crates/hir-ty/src/next_solver/infer/resolve.rs b/crates/hir-ty/src/next_solver/infer/resolve.rs
index 4bd3fbd..b6e5225 100644
--- a/crates/hir-ty/src/next_solver/infer/resolve.rs
+++ b/crates/hir-ty/src/next_solver/infer/resolve.rs
@@ -1,15 +1,14 @@
//! Things for resolving vars in the infer context of the next-trait-solver.
use rustc_type_ir::{
- ConstKind, FallibleTypeFolder, InferConst, InferTy, RegionKind, TyKind, TypeFoldable,
TypeFolder, TypeSuperFoldable, TypeVisitableExt,
data_structures::DelayedMap,
- inherent::{Const as _, IntoKind, Ty as _},
+ inherent::{Const as _, Ty as _},
};
use crate::next_solver::{Const, DbInterner, ErrorGuaranteed, Region, Ty};
-use super::{FixupError, FixupResult, InferCtxt};
+use super::InferCtxt;
///////////////////////////////////////////////////////////////////////////
// OPPORTUNISTIC VAR RESOLVER
diff --git a/crates/hir-ty/src/next_solver/infer/select.rs b/crates/hir-ty/src/next_solver/infer/select.rs
index 79b0a29..52ad410 100644
--- a/crates/hir-ty/src/next_solver/infer/select.rs
+++ b/crates/hir-ty/src/next_solver/infer/select.rs
@@ -1,3 +1,5 @@
+#![expect(dead_code, reason = "this is used by rustc")]
+
use std::ops::ControlFlow;
use hir_def::{ImplId, TraitId};
@@ -61,7 +63,7 @@
/// so they are noops when unioned with a definite error, and within
/// the categories it's easy to see that the unions are correct.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
-pub enum EvaluationResult {
+pub(crate) enum EvaluationResult {
/// Evaluation successful.
EvaluatedToOk,
/// Evaluation successful, but there were unevaluated region obligations.
@@ -91,17 +93,17 @@
impl EvaluationResult {
/// Returns `true` if this evaluation result is known to apply, even
/// considering outlives constraints.
- pub fn must_apply_considering_regions(self) -> bool {
+ pub(crate) fn must_apply_considering_regions(self) -> bool {
self == EvaluatedToOk
}
/// Returns `true` if this evaluation result is known to apply, ignoring
/// outlives constraints.
- pub fn must_apply_modulo_regions(self) -> bool {
+ pub(crate) fn must_apply_modulo_regions(self) -> bool {
self <= EvaluatedToOkModuloRegions
}
- pub fn may_apply(self) -> bool {
+ pub(crate) fn may_apply(self) -> bool {
match self {
EvaluatedToOkModuloOpaqueTypes
| EvaluatedToOk
@@ -113,7 +115,7 @@
}
}
- pub fn is_stack_dependent(self) -> bool {
+ pub(crate) fn is_stack_dependent(self) -> bool {
match self {
EvaluatedToAmbigStackDependent => true,
@@ -135,9 +137,9 @@
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SignatureMismatchData<'db> {
- pub found_trait_ref: TraitRef<'db>,
- pub expected_trait_ref: TraitRef<'db>,
- pub terr: TypeError<'db>,
+ pub(crate) found_trait_ref: TraitRef<'db>,
+ pub(crate) expected_trait_ref: TraitRef<'db>,
+ pub(crate) terr: TypeError<'db>,
}
/// When performing resolution, it is typically the case that there
@@ -147,7 +149,7 @@
/// - `Ok(None)`: could not definitely determine anything, usually due
/// to inconclusive type inference.
/// - `Err(e)`: error `e` occurred
-pub type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
+pub(crate) type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
/// Given the successful resolution of an obligation, the `ImplSource`
/// indicates where the impl comes from.
@@ -179,7 +181,7 @@
///
/// See explanation on `ImplSourceUserDefinedData`.
#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
-pub enum ImplSource<'db, N> {
+pub(crate) enum ImplSource<'db, N> {
/// ImplSource identifying a particular impl.
UserDefined(ImplSourceUserDefinedData<'db, N>),
@@ -194,28 +196,28 @@
}
impl<'db, N> ImplSource<'db, N> {
- pub fn nested_obligations(self) -> Vec<N> {
+ pub(crate) fn nested_obligations(self) -> Vec<N> {
match self {
ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
}
}
- pub fn borrow_nested_obligations(&self) -> &[N] {
+ pub(crate) fn borrow_nested_obligations(&self) -> &[N] {
match self {
ImplSource::UserDefined(i) => &i.nested,
ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
}
}
- pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
+ pub(crate) fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
match self {
ImplSource::UserDefined(i) => &mut i.nested,
ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
}
}
- pub fn map<M, F>(self, f: F) -> ImplSource<'db, M>
+ pub(crate) fn map<M, F>(self, f: F) -> ImplSource<'db, M>
where
F: FnMut(N) -> M,
{
@@ -244,15 +246,15 @@
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
-pub struct ImplSourceUserDefinedData<'db, N> {
+pub(crate) struct ImplSourceUserDefinedData<'db, N> {
#[type_visitable(ignore)]
#[type_foldable(identity)]
- pub impl_def_id: ImplId,
- pub args: GenericArgs<'db>,
- pub nested: Vec<N>,
+ pub(crate) impl_def_id: ImplId,
+ pub(crate) args: GenericArgs<'db>,
+ pub(crate) nested: Vec<N>,
}
-pub type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>;
+pub(crate) type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>;
impl<'db> InferCtxt<'db> {
pub(crate) fn select(
@@ -351,7 +353,9 @@
// Prefer dyn candidates over non-dyn candidates. This is necessary to
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
(
- CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
+ CandidateSource::Impl(_)
+ | CandidateSource::ParamEnv(_)
+ | CandidateSource::AliasBound(_),
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
) => true,
@@ -397,7 +401,9 @@
})
}
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
- CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested),
+ CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
+ ImplSource::Param(nested)
+ }
CandidateSource::CoherenceUnknowable => {
panic!("didn't expect to select an unknowable candidate")
}
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
index 7435357..5902f80 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
@@ -41,9 +41,7 @@
range.clone(),
iter_idx_range(range)
.map(|index| match table.probe_value(index) {
- ConstVariableValue::Known { value: _ } => {
- ConstVariableOrigin { param_def_id: None }
- }
+ ConstVariableValue::Known { value: _ } => ConstVariableOrigin {},
ConstVariableValue::Unknown { origin, universe: _ } => origin,
})
.collect(),
@@ -228,7 +226,6 @@
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
if let RegionKind::ReVar(vid) = r.kind() {
if self.snapshot_vars.region_vars.contains(&vid) {
- let idx = vid.index() - self.snapshot_vars.region_vars.start.index();
self.infcx.next_region_var()
} else {
r
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
index 05a1013..c8ec8da 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
@@ -1,7 +1,5 @@
//! Snapshotting in the infer ctxt of the next-trait-solver.
-use std::marker::PhantomData;
-
use ena::snapshot_vec as sv;
use ena::undo_log::{Rollback, UndoLogs};
use ena::unify as ut;
@@ -14,7 +12,6 @@
use crate::next_solver::infer::unify_key::ConstVidKey;
use crate::next_solver::infer::unify_key::RegionVidKey;
use crate::next_solver::infer::{InferCtxtInner, region_constraints, type_variable};
-use crate::traits;
pub struct Snapshot {
pub(crate) undo_len: usize,
@@ -31,6 +28,7 @@
FloatUnificationTable(sv::UndoLog<ut::Delegate<FloatVid>>),
RegionConstraintCollector(region_constraints::UndoLog<'db>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'db>>>),
+ #[expect(dead_code, reason = "this is used in rustc")]
PushRegionObligation,
}
diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs
index bc905c2..4f000c2 100644
--- a/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -9,17 +9,13 @@
use hir_def::TraitId;
use macros::{TypeFoldable, TypeVisitable};
+use rustc_type_ir::Upcast;
use rustc_type_ir::elaborate::Elaboratable;
-use rustc_type_ir::{
- PredicatePolarity, Upcast,
- solve::{Certainty, NoSolution},
-};
-use rustc_type_ir::{TypeFoldable, TypeVisitable};
use tracing::debug;
use crate::next_solver::{
- Binder, Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, Span,
- TraitPredicate, TraitRef, Ty,
+ Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, Span, TraitPredicate,
+ TraitRef, Ty,
};
use super::InferCtxt;
@@ -106,9 +102,9 @@
fn child_with_derived_cause(
&self,
clause: Clause<'db>,
- span: Span,
- parent_trait_pred: PolyTraitPredicate<'db>,
- index: usize,
+ _span: Span,
+ _parent_trait_pred: PolyTraitPredicate<'db>,
+ _index: usize,
) -> Self {
let cause = ObligationCause::new();
Obligation {
@@ -153,16 +149,16 @@
}
}
-pub type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>;
-pub type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>;
+pub(crate) type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>;
+pub(crate) type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>;
-pub type PredicateObligations<'db> = Vec<PredicateObligation<'db>>;
+pub(crate) type PredicateObligations<'db> = Vec<PredicateObligation<'db>>;
impl<'db> PredicateObligation<'db> {
/// Flips the polarity of the inner predicate.
///
/// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
- pub fn flip_polarity(&self, tcx: DbInterner<'db>) -> Option<PredicateObligation<'db>> {
+ pub fn flip_polarity(&self, _interner: DbInterner<'db>) -> Option<PredicateObligation<'db>> {
Some(PredicateObligation {
cause: self.cause.clone(),
param_env: self.param_env,
@@ -215,7 +211,7 @@
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
-pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
+pub(crate) fn type_known_to_meet_bound_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
diff --git a/crates/hir-ty/src/next_solver/infer/unify_key.rs b/crates/hir-ty/src/next_solver/infer/unify_key.rs
index dc913b2..a09f65f 100644
--- a/crates/hir-ty/src/next_solver/infer/unify_key.rs
+++ b/crates/hir-ty/src/next_solver/infer/unify_key.rs
@@ -6,18 +6,18 @@
use ena::unify::{NoError, UnifyKey, UnifyValue};
use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind};
-use crate::next_solver::{Const, Region, SolverDefId, Ty};
+use crate::next_solver::{Const, Region};
#[derive(Clone, Debug)]
-pub enum RegionVariableValue<'db> {
+pub(crate) enum RegionVariableValue<'db> {
Known { value: Region<'db> },
Unknown { universe: UniverseIndex },
}
#[derive(PartialEq, Copy, Clone, Debug)]
-pub struct RegionVidKey<'db> {
- pub vid: RegionVid,
- pub phantom: PhantomData<RegionVariableValue<'db>>,
+pub(crate) struct RegionVidKey<'db> {
+ pub(crate) vid: RegionVid,
+ pub(crate) phantom: PhantomData<RegionVariableValue<'db>>,
}
impl<'db> From<RegionVid> for RegionVidKey<'db> {
@@ -41,7 +41,7 @@
}
}
-pub struct RegionUnificationError;
+pub(crate) struct RegionUnificationError;
impl<'db> UnifyValue for RegionVariableValue<'db> {
type Error = RegionUnificationError;
@@ -90,15 +90,10 @@
// Generic consts.
#[derive(Copy, Clone, Debug)]
-pub struct ConstVariableOrigin {
- /// `DefId` of the const parameter this was instantiated for, if any.
- ///
- /// This should only be used for diagnostics.
- pub param_def_id: Option<SolverDefId>,
-}
+pub struct ConstVariableOrigin {}
#[derive(Clone, Debug)]
-pub enum ConstVariableValue<'db> {
+pub(crate) enum ConstVariableValue<'db> {
Known { value: Const<'db> },
Unknown { origin: ConstVariableOrigin, universe: UniverseIndex },
}
@@ -106,7 +101,7 @@
impl<'db> ConstVariableValue<'db> {
/// If this value is known, returns the const it is known to be.
/// Otherwise, `None`.
- pub fn known(&self) -> Option<Const<'db>> {
+ pub(crate) fn known(&self) -> Option<Const<'db>> {
match self {
ConstVariableValue::Unknown { .. } => None,
ConstVariableValue::Known { value } => Some(*value),
@@ -115,9 +110,9 @@
}
#[derive(PartialEq, Copy, Clone, Debug)]
-pub struct ConstVidKey<'db> {
- pub vid: ConstVid,
- pub phantom: PhantomData<Const<'db>>,
+pub(crate) struct ConstVidKey<'db> {
+ pub(crate) vid: ConstVid,
+ pub(crate) phantom: PhantomData<Const<'db>>,
}
impl<'db> From<ConstVid> for ConstVidKey<'db> {
diff --git a/crates/hir-ty/src/next_solver/inspect.rs b/crates/hir-ty/src/next_solver/inspect.rs
index 0db4746..d66aa9f 100644
--- a/crates/hir-ty/src/next_solver/inspect.rs
+++ b/crates/hir-ty/src/next_solver/inspect.rs
@@ -1,4 +1,4 @@
-pub use rustc_next_trait_solver::solve::inspect::*;
+pub(crate) use rustc_next_trait_solver::solve::inspect::*;
use rustc_ast_ir::try_visit;
use rustc_next_trait_solver::{
@@ -23,11 +23,11 @@
obligation_ctxt::ObligationCtxt,
};
-pub struct InspectConfig {
- pub max_depth: usize,
+pub(crate) struct InspectConfig {
+ pub(crate) max_depth: usize,
}
-pub struct InspectGoal<'a, 'db> {
+pub(crate) struct InspectGoal<'a, 'db> {
infcx: &'a SolverContext<'db>,
depth: usize,
orig_values: Vec<GenericArg<'db>>,
@@ -103,7 +103,7 @@
}
}
-pub struct InspectCandidate<'a, 'db> {
+pub(crate) struct InspectCandidate<'a, 'db> {
goal: &'a InspectGoal<'a, 'db>,
kind: inspect::ProbeKind<DbInterner<'db>>,
steps: Vec<&'a inspect::ProbeStep<DbInterner<'db>>>,
@@ -113,15 +113,15 @@
}
impl<'a, 'db> InspectCandidate<'a, 'db> {
- pub fn kind(&self) -> inspect::ProbeKind<DbInterner<'db>> {
+ pub(crate) fn kind(&self) -> inspect::ProbeKind<DbInterner<'db>> {
self.kind
}
- pub fn result(&self) -> Result<Certainty, NoSolution> {
+ pub(crate) fn result(&self) -> Result<Certainty, NoSolution> {
self.result.map(|c| c.value.certainty)
}
- pub fn goal(&self) -> &'a InspectGoal<'a, 'db> {
+ pub(crate) fn goal(&self) -> &'a InspectGoal<'a, 'db> {
self.goal
}
@@ -133,14 +133,17 @@
///
/// This is *not* the certainty of the candidate's full nested evaluation, which
/// can be accessed with [`Self::result`] instead.
- pub fn shallow_certainty(&self) -> Certainty {
+ pub(crate) fn shallow_certainty(&self) -> Certainty {
self.shallow_certainty
}
/// Visit all nested goals of this candidate without rolling
/// back their inference constraints. This function modifies
/// the state of the `infcx`.
- pub fn visit_nested_no_probe<V: ProofTreeVisitor<'db>>(&self, visitor: &mut V) -> V::Result {
+ pub(crate) fn visit_nested_no_probe<V: ProofTreeVisitor<'db>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
for goal in self.instantiate_nested_goals() {
try_visit!(goal.visit_with(visitor));
}
@@ -152,7 +155,7 @@
/// inference constraints. This function modifies the state of the `infcx`.
///
/// See [`Self::instantiate_impl_args`] if you need the impl args too.
- pub fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> {
+ pub(crate) fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();
@@ -200,7 +203,7 @@
/// Instantiate the args of an impl if this candidate came from a
/// `CandidateSource::Impl`. This function modifies the state of the
/// `infcx`.
- pub fn instantiate_impl_args(&self) -> GenericArgs<'db> {
+ pub(crate) fn instantiate_impl_args(&self) -> GenericArgs<'db> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();
@@ -241,7 +244,7 @@
panic!("expected impl args probe step for `instantiate_impl_args`");
}
- pub fn instantiate_proof_tree_for_nested_goal(
+ pub(crate) fn instantiate_proof_tree_for_nested_goal(
&self,
source: GoalSource,
goal: Goal<'db, Predicate<'db>>,
@@ -307,29 +310,33 @@
/// Visit all nested goals of this candidate, rolling back
/// all inference constraints.
- pub fn visit_nested_in_probe<V: ProofTreeVisitor<'db>>(&self, visitor: &mut V) -> V::Result {
+ #[expect(dead_code, reason = "used in rustc")]
+ pub(crate) fn visit_nested_in_probe<V: ProofTreeVisitor<'db>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
}
}
impl<'a, 'db> InspectGoal<'a, 'db> {
- pub fn infcx(&self) -> &'a InferCtxt<'db> {
+ pub(crate) fn infcx(&self) -> &'a InferCtxt<'db> {
self.infcx
}
- pub fn goal(&self) -> Goal<'db, Predicate<'db>> {
+ pub(crate) fn goal(&self) -> Goal<'db, Predicate<'db>> {
self.goal
}
- pub fn result(&self) -> Result<Certainty, NoSolution> {
+ pub(crate) fn result(&self) -> Result<Certainty, NoSolution> {
self.result
}
- pub fn source(&self) -> GoalSource {
+ pub(crate) fn source(&self) -> GoalSource {
self.source
}
- pub fn depth(&self) -> usize {
+ pub(crate) fn depth(&self) -> usize {
self.depth
}
@@ -405,7 +412,7 @@
}
}
- pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'db>> {
+ pub(crate) fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'db>> {
let mut candidates = vec![];
let mut nested_goals = vec![];
self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision);
@@ -415,7 +422,7 @@
/// Returns the single candidate applicable for the current goal, if it exists.
///
/// Returns `None` if there are either no or multiple applicable candidates.
- pub fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'db>> {
+ pub(crate) fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'db>> {
// FIXME(-Znext-solver): This does not handle impl candidates
// hidden by env candidates.
let mut candidates = self.candidates();
@@ -467,7 +474,7 @@
}
/// The public API to interact with proof trees.
-pub trait ProofTreeVisitor<'db> {
+pub(crate) trait ProofTreeVisitor<'db> {
type Result: VisitorResult;
fn config(&self) -> InspectConfig {
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 3fd8e7b..c1ccbaf 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -1,89 +1,68 @@
//! Things related to the Interner in the next-trait-solver.
-#![allow(unused)] // FIXME(next-solver): Remove this.
use std::{fmt, ops::ControlFlow};
+pub use tls_cache::clear_tls_solver_cache;
pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
use base_db::Crate;
-use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances};
use hir_def::{
- AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup,
- StructId, TypeAliasId, UnionId, VariantId,
+ AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId,
+ VariantId,
lang_item::LangItem,
signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags},
};
-use intern::sym::non_exhaustive;
-use intern::{Interned, impl_internable, sym};
use la_arena::Idx;
-use rustc_abi::{Align, ReprFlags, ReprOptions};
-use rustc_ast_ir::visit::VisitorResult;
+use rustc_abi::{ReprFlags, ReprOptions};
use rustc_hash::FxHashSet;
-use rustc_index::{IndexVec, bit_set::DenseBitSet};
+use rustc_index::bit_set::DenseBitSet;
use rustc_type_ir::{
- AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex,
- EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy,
- ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt,
- UniverseIndex, Upcast, Variance, WithCachedTypeInfo,
- elaborate::{self, elaborate},
+ AliasTermKind, AliasTyKind, BoundVar, CollectAndApply, CoroutineWitnessTypes, DebruijnIndex,
+ EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, Interner, TraitRef,
+ TypeVisitableExt, UniverseIndex, Upcast, Variance,
+ elaborate::elaborate,
error::TypeError,
- inherent::{
- self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _,
- Region as _, SliceLike as _, Span as _, Ty as _,
- },
- ir_print,
+ inherent::{self, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _},
lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem},
- relate,
solve::SizedTraitKind,
};
-use salsa::plumbing::AsId;
-use smallvec::{SmallVec, smallvec};
-use syntax::ast::SelfParamKind;
-use tracing::debug;
-use triomphe::Arc;
use crate::{
- ConstScalar, FnAbi, Interner,
- db::HirDatabase,
- lower_nextsolver::{self, TyLoweringContext},
+ FnAbi,
+ db::{HirDatabase, InternedCoroutine},
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint},
next_solver::{
AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
- CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug,
+ CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, OpaqueTypeKey,
RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper,
- TypingMode,
- infer::{
- DbInternerInferExt, InferCtxt,
- traits::{Obligation, ObligationCause},
- },
- obligation_ctxt::ObligationCtxt,
util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls},
},
};
use super::{
- Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause,
- ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints,
- ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv,
- ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate,
- PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst,
+ Binder, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, ClauseKind, Clauses, Const,
+ ErrorGuaranteed, ExprConst, ExternalConstraints, GenericArg, GenericArgs, ParamConst, ParamEnv,
+ ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, Predicate, SolverDefId, Term, Ty,
+ TyKind, Tys, Valtree, ValueConst,
abi::Safety,
fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate},
generics::{Generics, generics},
- mapping::ChalkToNextSolver,
region::{
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region,
},
util::sizedness_constraint_for_ty,
};
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
+pub struct InternedWrapperNoDebug<T>(pub(crate) T);
+
#[macro_export]
#[doc(hidden)]
macro_rules! _interned_vec_nolifetime_salsa {
($name:ident, $ty:ty) => {
interned_vec_nolifetime_salsa!($name, $ty, nofold);
- impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name {
+ impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
self,
folder: &mut F,
@@ -104,7 +83,7 @@
}
}
- impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name {
+ impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
&self,
visitor: &mut V,
@@ -117,14 +96,14 @@
}
};
($name:ident, $ty:ty, nofold) => {
- #[salsa::interned(no_lifetime, constructor = new_, debug)]
+ #[salsa::interned(constructor = new_, debug)]
pub struct $name {
#[returns(ref)]
inner_: smallvec::SmallVec<[$ty; 2]>,
}
- impl $name {
- pub fn new_from_iter<'db>(
+ impl<'db> $name<'db> {
+ pub fn new_from_iter(
interner: DbInterner<'db>,
data: impl IntoIterator<Item = $ty>,
) -> Self {
@@ -140,7 +119,7 @@
}
}
- impl rustc_type_ir::inherent::SliceLike for $name {
+ impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
type Item = $ty;
type IntoIter = <smallvec::SmallVec<[$ty; 2]> as IntoIterator>::IntoIter;
@@ -154,7 +133,7 @@
}
}
- impl IntoIterator for $name {
+ impl<'db> IntoIterator for $name<'db> {
type Item = $ty;
type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter;
@@ -163,7 +142,7 @@
}
}
- impl Default for $name {
+ impl<'db> Default for $name<'db> {
fn default() -> Self {
$name::new_from_iter(DbInterner::conjure(), [])
}
@@ -631,12 +610,11 @@
self,
interner: DbInterner<'db>,
) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> {
- let db = interner.db();
let hir_def::AdtId::StructId(struct_id) = self.inner().id else {
return None;
};
let id: VariantId = struct_id.into();
- let field_types = interner.db().field_types_ns(id);
+ let field_types = interner.db().field_types(id);
field_types.iter().last().map(|f| *f.1)
}
@@ -647,23 +625,10 @@
) -> EarlyBinder<DbInterner<'db>, impl IntoIterator<Item = Ty<'db>>> {
let db = interner.db();
// FIXME: this is disabled just to match the behavior with chalk right now
- let field_tys = |id: VariantId| {
- let variant_data = id.fields(db);
- let fields = if variant_data.fields().is_empty() {
- vec![]
- } else {
- let field_types = db.field_types_ns(id);
- variant_data
- .fields()
- .iter()
- .map(|(idx, _)| {
- let ty = field_types[idx];
- ty.skip_binder()
- })
- .collect()
- };
+ let _field_tys = |id: VariantId| {
+ db.field_types(id).iter().map(|(_, ty)| ty.skip_binder()).collect::<Vec<_>>()
};
- let field_tys = |id: VariantId| vec![];
+ let field_tys = |_id: VariantId| vec![];
let tys: Vec<_> = match self.inner().id {
hir_def::AdtId::StructId(id) => field_tys(id.into()),
hir_def::AdtId::UnionId(id) => field_tys(id.into()),
@@ -696,7 +661,7 @@
fn destructor(
self,
- interner: DbInterner<'db>,
+ _interner: DbInterner<'db>,
) -> Option<rustc_type_ir::solve::AdtDestructorKind> {
// FIXME(next-solver)
None
@@ -742,7 +707,7 @@
false
}
- fn feature_bound_holds_in_crate(self, symbol: ()) -> bool {
+ fn feature_bound_holds_in_crate(self, _symbol: ()) -> bool {
false
}
}
@@ -884,10 +849,10 @@
}};
}
-impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
+impl<'db> Interner for DbInterner<'db> {
type DefId = SolverDefId;
type LocalDefId = SolverDefId;
- type LocalDefIds = SolverDefIds;
+ type LocalDefIds = SolverDefIds<'db>;
type TraitId = TraitIdWrapper;
type ForeignId = TypeAliasIdWrapper;
type FunctionId = CallableIdWrapper;
@@ -904,16 +869,16 @@
type Term = Term<'db>;
- type BoundVarKinds = BoundVarKinds;
+ type BoundVarKinds = BoundVarKinds<'db>;
type BoundVarKind = BoundVarKind;
type PredefinedOpaques = PredefinedOpaques<'db>;
fn mk_predefined_opaques_in_body(
self,
- data: rustc_type_ir::solve::PredefinedOpaquesData<Self>,
+ data: &[(OpaqueTypeKey<'db>, Self::Ty)],
) -> Self::PredefinedOpaques {
- PredefinedOpaques::new(self, data)
+ PredefinedOpaques::new_from_iter(self, data.iter().cloned())
}
type CanonicalVarKinds = CanonicalVars<'db>;
@@ -977,7 +942,7 @@
type GenericsOf = Generics;
- type VariancesOf = VariancesOf;
+ type VariancesOf = VariancesOf<'db>;
type AdtDef = AdtDef;
@@ -1002,7 +967,7 @@
fn mk_tracked<T: fmt::Debug + Clone>(
self,
data: T,
- dep_node: Self::DepNodeIndex,
+ _dep_node: Self::DepNodeIndex,
) -> Self::Tracked<T> {
Tracked(data)
}
@@ -1024,15 +989,15 @@
fn canonical_param_env_cache_get_or_insert<R>(
self,
- param_env: Self::ParamEnv,
+ _param_env: Self::ParamEnv,
f: impl FnOnce() -> rustc_type_ir::CanonicalParamEnvCacheEntry<Self>,
from_entry: impl FnOnce(&rustc_type_ir::CanonicalParamEnvCacheEntry<Self>) -> R,
) -> R {
from_entry(&f())
}
- fn evaluation_is_concurrent(&self) -> bool {
- false
+ fn assert_evaluation_is_concurrent(&self) {
+ panic!("evaluation shouldn't be concurrent yet")
}
fn expand_abstract_consts<T: rustc_type_ir::TypeFoldable<Self>>(self, _: T) -> T {
@@ -1045,10 +1010,9 @@
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
let generic_def = match def_id {
- SolverDefId::FunctionId(def_id) => def_id.into(),
- SolverDefId::AdtId(def_id) => def_id.into(),
- SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
- SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(),
+ SolverDefId::Ctor(Ctor::Enum(def_id)) | SolverDefId::EnumVariantId(def_id) => {
+ def_id.loc(self.db).parent.into()
+ }
SolverDefId::InternedOpaqueTyId(_def_id) => {
// FIXME(next-solver): track variances
//
@@ -1059,17 +1023,20 @@
(0..self.generics_of(def_id).count()).map(|_| Variance::Invariant),
);
}
- _ => return VariancesOf::new_from_iter(self, []),
+ SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
+ SolverDefId::AdtId(def_id) => def_id.into(),
+ SolverDefId::FunctionId(def_id) => def_id.into(),
+ SolverDefId::ConstId(_)
+ | SolverDefId::StaticId(_)
+ | SolverDefId::TraitId(_)
+ | SolverDefId::TypeAliasId(_)
+ | SolverDefId::ImplId(_)
+ | SolverDefId::InternedClosureId(_)
+ | SolverDefId::InternedCoroutineId(_) => {
+ return VariancesOf::new_from_iter(self, []);
+ }
};
- VariancesOf::new_from_iter(
- self,
- self.db()
- .variances_of(generic_def)
- .as_deref()
- .unwrap_or_default()
- .iter()
- .map(|v| v.to_nextsolver(self)),
- )
+ self.db.variances_of(generic_def)
}
fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> {
@@ -1160,17 +1127,17 @@
(TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args)
}
- fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool {
+ fn check_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) -> bool {
// FIXME
true
}
- fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) {}
+ fn debug_assert_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) {}
fn debug_assert_existential_args_compatible(
self,
- def_id: Self::DefId,
- args: Self::GenericArgs,
+ _def_id: Self::DefId,
+ _args: Self::GenericArgs,
) {
}
@@ -1211,6 +1178,7 @@
| SolverDefId::AdtId(_)
| SolverDefId::TraitId(_)
| SolverDefId::ImplId(_)
+ | SolverDefId::EnumVariantId(..)
| SolverDefId::Ctor(..)
| SolverDefId::InternedOpaqueTyId(..) => panic!(),
};
@@ -1238,11 +1206,27 @@
}
fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability {
- unimplemented!()
+ // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+ // the current infer query, except with revealed opaques - is it rare enough to not matter?
+ let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+ let body = self.db.body(owner);
+ let expr = &body[expr_id];
+ match *expr {
+ hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind {
+ hir_def::hir::ClosureKind::Coroutine(movability) => match movability {
+ hir_def::hir::Movability::Static => rustc_ast_ir::Movability::Static,
+ hir_def::hir::Movability::Movable => rustc_ast_ir::Movability::Movable,
+ },
+ hir_def::hir::ClosureKind::Async => rustc_ast_ir::Movability::Static,
+ _ => panic!("unexpected expression for a coroutine: {expr:?}"),
+ },
+ hir_def::hir::Expr::Async { .. } => rustc_ast_ir::Movability::Static,
+ _ => panic!("unexpected expression for a coroutine: {expr:?}"),
+ }
}
- fn coroutine_for_closure(self, def_id: Self::CoroutineId) -> Self::CoroutineId {
- unimplemented!()
+ fn coroutine_for_closure(self, def_id: Self::CoroutineClosureId) -> Self::CoroutineId {
+ def_id
}
fn generics_require_sized_self(self, def_id: Self::DefId) -> bool {
@@ -1319,7 +1303,7 @@
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
- let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap());
+ let predicates = self.db().generic_predicates(def_id.try_into().unwrap());
let predicates: Vec<_> = predicates.iter().cloned().collect();
EarlyBinder::bind(predicates.into_iter())
}
@@ -1346,7 +1330,7 @@
let predicates: Vec<(Clause<'db>, Span)> = self
.db()
- .generic_predicates_ns(def_id.0.into())
+ .generic_predicates(def_id.0.into())
.iter()
.filter(|p| match p.kind().skip_binder() {
// rustc has the following assertion:
@@ -1380,7 +1364,7 @@
let predicates: Vec<(Clause<'db>, Span)> = self
.db()
- .generic_predicates_ns(def_id.try_into().unwrap())
+ .generic_predicates(def_id.try_into().unwrap())
.iter()
.filter(|p| match p.kind().skip_binder() {
rustc_type_ir::ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
@@ -1418,9 +1402,10 @@
})
}
+ #[expect(unreachable_code)]
fn const_conditions(
self,
- def_id: Self::DefId,
+ _def_id: Self::DefId,
) -> EarlyBinder<
Self,
impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>,
@@ -1428,7 +1413,7 @@
EarlyBinder::bind([unimplemented!()])
}
- fn has_target_features(self, def_id: Self::FunctionId) -> bool {
+ fn has_target_features(self, _def_id: Self::FunctionId) -> bool {
false
}
@@ -1459,7 +1444,7 @@
hir_def::lang_item::LangItemTarget::Union(union_id) => union_id.into(),
hir_def::lang_item::LangItemTarget::TypeAlias(type_alias_id) => type_alias_id.into(),
hir_def::lang_item::LangItemTarget::Trait(trait_id) => trait_id.into(),
- hir_def::lang_item::LangItemTarget::EnumVariant(enum_variant_id) => unimplemented!(),
+ hir_def::lang_item::LangItemTarget::EnumVariant(_) => unimplemented!(),
}
}
@@ -1549,7 +1534,6 @@
CoroutineReturn,
CoroutineYield,
FutureOutput,
- AsyncFnOnceOutput,
CallRefFuture,
CallOnceFuture,
AsyncFnOnceOutput,
@@ -1593,7 +1577,6 @@
AsyncFnMut,
AsyncFnOnce,
AsyncFnOnceOutput,
- AsyncFnOnceOutput,
)
}
@@ -1633,7 +1616,7 @@
};
if fps.is_empty() {
- for_trait_impls(
+ _ = for_trait_impls(
self.db(),
self.krate.expect("Must have self.krate"),
self.block,
@@ -1655,7 +1638,7 @@
},
);
} else {
- for_trait_impls(
+ _ = for_trait_impls(
self.db(),
self.krate.expect("Must have self.krate"),
self.block,
@@ -1695,7 +1678,7 @@
}
}
- fn has_item_definition(self, def_id: Self::DefId) -> bool {
+ fn has_item_definition(self, _def_id: Self::DefId) -> bool {
// FIXME(next-solver): should check if the associated item has a value.
true
}
@@ -1743,13 +1726,13 @@
trait_data.flags.contains(TraitFlags::FUNDAMENTAL)
}
- fn trait_may_be_implemented_via_object(self, trait_def_id: Self::TraitId) -> bool {
+ fn trait_may_be_implemented_via_object(self, _trait_def_id: Self::TraitId) -> bool {
// FIXME(next-solver): should check the `TraitFlags` for
// the `#[rustc_do_not_implement_via_object]` flag
true
}
- fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool {
+ fn is_impl_trait_in_trait(self, _def_id: Self::DefId) -> bool {
// FIXME(next-solver)
false
}
@@ -1758,23 +1741,39 @@
panic!("Bug encountered in next-trait-solver: {}", msg.to_string())
}
- fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool {
- // FIXME(next-solver)
- true
+ fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool {
+ // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+ // the current infer query, except with revealed opaques - is it rare enough to not matter?
+ let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+ let body = self.db.body(owner);
+ matches!(
+ body[expr_id],
+ hir_def::hir::Expr::Closure {
+ closure_kind: hir_def::hir::ClosureKind::Coroutine(_),
+ ..
+ }
+ )
}
- fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool {
- // FIXME(next-solver)
- true
+ fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool {
+ // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+ // the current infer query, except with revealed opaques - is it rare enough to not matter?
+ let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+ let body = self.db.body(owner);
+ matches!(
+ body[expr_id],
+ hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. }
+ | hir_def::hir::Expr::Async { .. }
+ )
}
- fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool {
- // FIXME(next-solver)
+ fn coroutine_is_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool {
+ // We don't handle gen coroutines yet.
false
}
- fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool {
- // FIXME(next-solver)
+ fn coroutine_is_async_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool {
+ // We don't handle gen coroutines yet.
false
}
@@ -1801,7 +1800,7 @@
return UnsizingParams(DenseBitSet::new_empty(num_params));
};
- let field_types = self.db().field_types_ns(variant.id());
+ let field_types = self.db().field_types(variant.id());
let mut unsizing_params = DenseBitSet::new_empty(num_params);
let ty = field_types[tail_field.0];
for arg in ty.instantiate_identity().walk() {
@@ -1867,19 +1866,19 @@
Binder::bind_with_vars(inner, bound_vars)
}
- fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
+ fn opaque_types_defined_by(self, _defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
// FIXME(next-solver)
SolverDefIds::new_from_iter(self, [])
}
- fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool {
+ fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool {
// FIXME(next-solver)
false
}
fn explicit_implied_const_bounds(
self,
- def_id: Self::DefId,
+ _def_id: Self::DefId,
) -> EarlyBinder<
Self,
impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>,
@@ -1896,14 +1895,14 @@
self.db().function_signature(id).flags.contains(FnFlags::CONST)
}
- fn impl_is_const(self, def_id: Self::ImplId) -> bool {
+ fn impl_is_const(self, _def_id: Self::ImplId) -> bool {
false
}
fn opt_alias_variances(
self,
- kind: impl Into<rustc_type_ir::AliasTermKind>,
- def_id: Self::DefId,
+ _kind: impl Into<rustc_type_ir::AliasTermKind>,
+ _def_id: Self::DefId,
) -> Option<Self::VariancesOf> {
None
}
@@ -1915,10 +1914,9 @@
match impl_trait_id {
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
let infer = self.db().infer(func.into());
- EarlyBinder::bind(infer.type_of_rpit[idx.to_nextsolver(self)])
+ EarlyBinder::bind(infer.type_of_rpit[idx])
}
- crate::ImplTraitId::TypeAliasImplTrait(..)
- | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
+ crate::ImplTraitId::TypeAliasImplTrait(..) => {
// FIXME(next-solver)
EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed))
}
@@ -1930,11 +1928,13 @@
fn coroutine_hidden_types(
self,
- def_id: Self::CoroutineId,
- ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::CoroutineWitnessTypes<Self>>>
- {
- // FIXME(next-solver)
- unimplemented!()
+ _def_id: Self::CoroutineId,
+ ) -> EarlyBinder<Self, Binder<'db, CoroutineWitnessTypes<Self>>> {
+ // FIXME: Actually implement this.
+ EarlyBinder::bind(Binder::dummy(CoroutineWitnessTypes {
+ types: Tys::default(),
+ assumptions: RegionAssumptions::default(),
+ }))
}
fn is_default_trait(self, def_id: Self::TraitId) -> bool {
@@ -1949,7 +1949,7 @@
self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE)
}
- fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool {
+ fn impl_self_is_guaranteed_unsized(self, _def_id: Self::ImplId) -> bool {
false
}
@@ -1958,7 +1958,11 @@
specializing_impl_def_id: Self::ImplId,
parent_impl_def_id: Self::ImplId,
) -> bool {
- false
+ crate::specialization::specializes(
+ self.db,
+ specializing_impl_def_id.0,
+ parent_impl_def_id.0,
+ )
}
fn next_trait_solver_globally(self) -> bool {
@@ -1967,10 +1971,9 @@
fn opaque_types_and_coroutines_defined_by(
self,
- defining_anchor: Self::LocalDefId,
+ _defining_anchor: Self::LocalDefId,
) -> Self::LocalDefIds {
- // FIXME(next-solver)
- unimplemented!()
+ Default::default()
}
type Probe = rustc_type_ir::solve::inspect::Probe<DbInterner<'db>>;
@@ -1986,6 +1989,13 @@
Self,
>(self, canonical_goal)
}
+
+ fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool {
+ matches!(
+ self.as_trait_lang_item(def_id),
+ Some(SolverTraitLangItem::Sized | SolverTraitLangItem::MetaSized)
+ )
+ }
}
impl<'db> DbInterner<'db> {
@@ -2273,4 +2283,12 @@
})
})
}
+
+ /// Clears the thread-local trait solver cache.
+ ///
+ /// Should be called before getting memory usage estimations, as the solver cache
+ /// is per-revision and usually should be excluded from estimations.
+ pub fn clear_tls_solver_cache() {
+ GLOBAL_CACHE.with_borrow_mut(|handle| *handle = None);
+ }
}
diff --git a/crates/hir-ty/src/next_solver/ir_print.rs b/crates/hir-ty/src/next_solver/ir_print.rs
index 69afcf5..dab0fe9 100644
--- a/crates/hir-ty/src/next_solver/ir_print.rs
+++ b/crates/hir-ty/src/next_solver/ir_print.rs
@@ -5,8 +5,6 @@
use rustc_type_ir::inherent::SliceLike;
use rustc_type_ir::{self as ty, ir_print::IrPrint};
-use crate::db::HirDatabase;
-
use super::SolverDefId;
use super::interner::DbInterner;
diff --git a/crates/hir-ty/src/next_solver/mapping.rs b/crates/hir-ty/src/next_solver/mapping.rs
deleted file mode 100644
index 1a5982c..0000000
--- a/crates/hir-ty/src/next_solver/mapping.rs
+++ /dev/null
@@ -1,1779 +0,0 @@
-//! Things useful for mapping to/from Chalk and next-trait-solver types.
-
-use base_db::Crate;
-use chalk_ir::{
- CanonicalVarKind, CanonicalVarKinds, FnPointer, InferenceVar, Substitution, TyVariableKind,
- WellFormed, cast::Cast, fold::Shift, interner::HasInterner,
-};
-use hir_def::{
- CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId,
- TypeOrConstParamId, TypeParamId, signatures::TraitFlags,
-};
-use hir_def::{GenericDefId, GenericParamId};
-use intern::sym;
-use rustc_type_ir::{
- AliasTerm, BoundVar, DebruijnIndex, ExistentialProjection, ExistentialTraitRef, Interner as _,
- OutlivesPredicate, ProjectionPredicate, TypeFoldable, TypeSuperFoldable, TypeVisitable,
- TypeVisitableExt, UniverseIndex, elaborate,
- inherent::{BoundVarLike, Clause as _, IntoKind, PlaceholderLike, SliceLike, Ty as _},
- shift_vars,
- solve::Goal,
-};
-use salsa::plumbing::FromId;
-use salsa::{Id, plumbing::AsId};
-
-use crate::next_solver::BoundConst;
-use crate::{
- ConstScalar, ImplTraitId, Interner, MemoryMap,
- db::{
- HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId,
- InternedOpaqueTyId, InternedTypeOrConstParamId,
- },
- from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
- mapping::ToChalk,
- next_solver::{
- Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst,
- interner::{AdtDef, BoundVarKind, BoundVarKinds, DbInterner},
- },
- to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
-};
-use crate::{
- from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_placeholder_idx,
-};
-
-use super::{
- BoundExistentialPredicate, BoundExistentialPredicates, BoundRegion, BoundRegionKind, BoundTy,
- BoundTyKind, Canonical, CanonicalVars, Clause, Clauses, Const, Ctor, EarlyParamRegion,
- ErrorGuaranteed, ExistentialPredicate, GenericArg, GenericArgs, ParamConst, ParamEnv, ParamTy,
- Placeholder, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind,
- Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, Tys, ValueConst, VariancesOf,
-};
-
-// FIXME: This should urgently go (as soon as we finish the migration off Chalk, that is).
-pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>>(
- interner: DbInterner<'db>,
- def: GenericDefId,
- binder: rustc_type_ir::Binder<DbInterner<'db>, T>,
-) -> rustc_type_ir::EarlyBinder<DbInterner<'db>, T> {
- let mut folder = BinderToEarlyBinder {
- interner,
- debruijn: rustc_type_ir::DebruijnIndex::ZERO,
- params: crate::generics::generics(interner.db, def).iter_id().collect(),
- };
- rustc_type_ir::EarlyBinder::bind(binder.skip_binder().fold_with(&mut folder))
-}
-
-struct BinderToEarlyBinder<'db> {
- interner: DbInterner<'db>,
- debruijn: rustc_type_ir::DebruijnIndex,
- params: Vec<GenericParamId>,
-}
-
-impl<'db> rustc_type_ir::TypeFolder<DbInterner<'db>> for BinderToEarlyBinder<'db> {
- fn cx(&self) -> DbInterner<'db> {
- self.interner
- }
-
- fn fold_binder<T>(
- &mut self,
- t: rustc_type_ir::Binder<DbInterner<'db>, T>,
- ) -> rustc_type_ir::Binder<DbInterner<'db>, T>
- where
- T: TypeFoldable<DbInterner<'db>>,
- {
- self.debruijn.shift_in(1);
- let result = t.super_fold_with(self);
- self.debruijn.shift_out(1);
- result
- }
-
- fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
- match t.kind() {
- rustc_type_ir::TyKind::Bound(debruijn, bound_ty) if self.debruijn == debruijn => {
- let var: rustc_type_ir::BoundVar = bound_ty.var();
- let GenericParamId::TypeParamId(id) = self.params[bound_ty.var.as_usize()] else {
- unreachable!()
- };
- Ty::new(
- self.cx(),
- rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32(), id }),
- )
- }
- _ => t.super_fold_with(self),
- }
- }
-
- fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
- match r.kind() {
- rustc_type_ir::ReBound(debruijn, bound_region) if self.debruijn == debruijn => {
- let var: rustc_type_ir::BoundVar = bound_region.var();
- let GenericParamId::LifetimeParamId(id) = self.params[bound_region.var.as_usize()]
- else {
- unreachable!()
- };
- Region::new(
- self.cx(),
- rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion {
- index: var.as_u32(),
- id,
- }),
- )
- }
- _ => r,
- }
- }
-
- fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
- match c.kind() {
- rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => {
- let GenericParamId::ConstParamId(id) = self.params[var.var.as_usize()] else {
- unreachable!()
- };
- Const::new(
- self.cx(),
- rustc_type_ir::ConstKind::Param(ParamConst { index: var.var.as_u32(), id }),
- )
- }
- _ => c.super_fold_with(self),
- }
- }
-}
-
-pub trait ChalkToNextSolver<'db, Out> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out;
-}
-
-impl<'db, A, OutA, B, OutB> ChalkToNextSolver<'db, (OutA, OutB)> for (A, B)
-where
- A: ChalkToNextSolver<'db, OutA>,
- B: ChalkToNextSolver<'db, OutB>,
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> (OutA, OutB) {
- (self.0.to_nextsolver(interner), self.1.to_nextsolver(interner))
- }
-}
-
-pub trait NextSolverToChalk<'db, Out> {
- fn to_chalk(self, interner: DbInterner<'db>) -> Out;
-}
-
-impl<'db, T, Out> NextSolverToChalk<'db, Option<Out>> for Option<T>
-where
- T: NextSolverToChalk<'db, Out>,
-{
- fn to_chalk(self, interner: DbInterner<'db>) -> Option<Out> {
- self.map(|it| it.to_chalk(interner))
- }
-}
-
-impl NextSolverToChalk<'_, chalk_ir::Mutability> for rustc_ast_ir::Mutability {
- fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Mutability {
- match self {
- rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
- rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
- }
- }
-}
-
-impl NextSolverToChalk<'_, chalk_ir::Safety> for crate::next_solver::abi::Safety {
- fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Safety {
- match self {
- crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
- crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Ty<'db> {
- Ty::new(
- interner,
- match self.kind(Interner) {
- chalk_ir::TyKind::Adt(adt_id, substitution) => {
- let def = AdtDef::new(adt_id.0, interner);
- let args = substitution.to_nextsolver(interner);
- rustc_type_ir::TyKind::Adt(def, args)
- }
- chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution) => {
- let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(*assoc_type_id));
- let args: GenericArgs<'db> = substitution.to_nextsolver(interner);
- let alias_ty = rustc_type_ir::AliasTy::new(interner, def_id, args.iter());
- rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias_ty)
- }
- chalk_ir::TyKind::Scalar(scalar) => match scalar {
- chalk_ir::Scalar::Bool => rustc_type_ir::TyKind::Bool,
- chalk_ir::Scalar::Char => rustc_type_ir::TyKind::Char,
- chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize)
- }
- chalk_ir::Scalar::Int(chalk_ir::IntTy::I8) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8)
- }
- chalk_ir::Scalar::Int(chalk_ir::IntTy::I16) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16)
- }
- chalk_ir::Scalar::Int(chalk_ir::IntTy::I32) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32)
- }
- chalk_ir::Scalar::Int(chalk_ir::IntTy::I64) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64)
- }
- chalk_ir::Scalar::Int(chalk_ir::IntTy::I128) => {
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::U16) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::U64) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64)
- }
- chalk_ir::Scalar::Uint(chalk_ir::UintTy::U128) => {
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128)
- }
- chalk_ir::Scalar::Float(chalk_ir::FloatTy::F16) => {
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16)
- }
- chalk_ir::Scalar::Float(chalk_ir::FloatTy::F32) => {
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32)
- }
- chalk_ir::Scalar::Float(chalk_ir::FloatTy::F64) => {
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64)
- }
- chalk_ir::Scalar::Float(chalk_ir::FloatTy::F128) => {
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128)
- }
- },
- chalk_ir::TyKind::Tuple(_, substitution) => {
- let args = substitution.to_nextsolver(interner);
- rustc_type_ir::TyKind::Tuple(args)
- }
- chalk_ir::TyKind::Array(ty, len) => rustc_type_ir::TyKind::Array(
- ty.to_nextsolver(interner),
- len.to_nextsolver(interner),
- ),
- chalk_ir::TyKind::Slice(ty) => {
- rustc_type_ir::TyKind::Slice(ty.to_nextsolver(interner))
- }
- chalk_ir::TyKind::Raw(mutability, ty) => rustc_type_ir::RawPtr(
- ty.to_nextsolver(interner),
- mutability.to_nextsolver(interner),
- ),
- chalk_ir::TyKind::Ref(mutability, lifetime, ty) => rustc_type_ir::TyKind::Ref(
- lifetime.to_nextsolver(interner),
- ty.to_nextsolver(interner),
- mutability.to_nextsolver(interner),
- ),
- chalk_ir::TyKind::OpaqueType(def_id, substitution) => {
- let id: InternedOpaqueTyId = (*def_id).into();
- let args: GenericArgs<'db> = substitution.to_nextsolver(interner);
- let alias_ty = rustc_type_ir::AliasTy::new(interner, id.into(), args);
- rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty)
- }
- chalk_ir::TyKind::FnDef(fn_def_id, substitution) => {
- let def_id = CallableDefId::from_chalk(interner.db(), *fn_def_id);
- rustc_type_ir::TyKind::FnDef(
- def_id.into(),
- substitution.to_nextsolver(interner),
- )
- }
- chalk_ir::TyKind::Str => rustc_type_ir::TyKind::Str,
- chalk_ir::TyKind::Never => rustc_type_ir::TyKind::Never,
- chalk_ir::TyKind::Closure(closure_id, substitution) => {
- let id: InternedClosureId = (*closure_id).into();
- rustc_type_ir::TyKind::Closure(id.into(), substitution.to_nextsolver(interner))
- }
- chalk_ir::TyKind::Coroutine(coroutine_id, substitution) => {
- let id: InternedCoroutineId = (*coroutine_id).into();
- rustc_type_ir::TyKind::Coroutine(
- id.into(),
- substitution.to_nextsolver(interner),
- )
- }
- chalk_ir::TyKind::CoroutineWitness(coroutine_id, substitution) => {
- let id: InternedCoroutineId = (*coroutine_id).into();
- rustc_type_ir::TyKind::CoroutineWitness(
- id.into(),
- substitution.to_nextsolver(interner),
- )
- }
- chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign(
- crate::from_foreign_def_id(*foreign_def_id).into(),
- ),
- chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed),
- chalk_ir::TyKind::Dyn(dyn_ty) => {
- // exists<type> { for<...> ^1.0: ... }
- let bounds = BoundExistentialPredicates::new_from_iter(
- interner,
- dyn_ty.bounds.skip_binders().iter(Interner).filter_map(|pred| {
- // for<...> ^1.0: ...
- let (val, binders) = pred.clone().into_value_and_skipped_binders();
- let bound_vars = binders.to_nextsolver(interner);
- let clause = match val {
- chalk_ir::WhereClause::Implemented(trait_ref) => {
- let trait_id = from_chalk_trait_id(trait_ref.trait_id);
- if interner
- .db()
- .trait_signature(trait_id)
- .flags
- .contains(TraitFlags::AUTO)
- {
- ExistentialPredicate::AutoTrait(trait_id.into())
- } else {
- let args = GenericArgs::new_from_iter(
- interner,
- trait_ref
- .substitution
- .iter(Interner)
- .skip(1)
- .map(|a| a.clone().shifted_out(Interner).unwrap())
- .map(|a| a.to_nextsolver(interner)),
- );
- let trait_ref = ExistentialTraitRef::new_from_args(
- interner, trait_id.into(), args,
- );
- ExistentialPredicate::Trait(trait_ref)
- }
- }
- chalk_ir::WhereClause::AliasEq(alias_eq) => {
- let (def_id, args) = match &alias_eq.alias {
- chalk_ir::AliasTy::Projection(projection) => {
- let id =
- from_assoc_type_id(projection.associated_ty_id);
- let def_id = SolverDefId::TypeAliasId(id);
- let generics = interner.generics_of(def_id);
- let parent_len = generics.parent_count;
- let substs = projection.substitution.iter(Interner).skip(1);
-
- let args = GenericArgs::new_from_iter(
- interner,
- substs
- .map(|a| {
- a.clone().shifted_out(Interner).unwrap()
- })
- .map(|a| a.to_nextsolver(interner)),
- );
- (def_id, args)
- }
- chalk_ir::AliasTy::Opaque(opaque_ty) => {
- panic!("Invalid ExistentialPredicate (opaques can't be named).");
- }
- };
- let term = alias_eq
- .ty
- .clone()
- .shifted_out(Interner)
- .unwrap()
- .to_nextsolver(interner)
- .into();
- let projection = ExistentialProjection::new_from_args(
- interner, def_id, args, term,
- );
- ExistentialPredicate::Projection(projection)
- }
- chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
- return None;
- }
- chalk_ir::WhereClause::TypeOutlives(type_outlives) => return None,
- };
-
- Some(Binder::bind_with_vars(clause, bound_vars))
- }),
- );
- let region = dyn_ty.lifetime.to_nextsolver(interner);
- rustc_type_ir::TyKind::Dynamic(bounds, region)
- }
- chalk_ir::TyKind::Alias(alias_ty) => match alias_ty {
- chalk_ir::AliasTy::Projection(projection_ty) => {
- let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(
- projection_ty.associated_ty_id,
- ));
- let alias_ty = rustc_type_ir::AliasTy::new_from_args(
- interner,
- def_id,
- projection_ty.substitution.to_nextsolver(interner),
- );
- rustc_type_ir::TyKind::Alias(
- rustc_type_ir::AliasTyKind::Projection,
- alias_ty,
- )
- }
- chalk_ir::AliasTy::Opaque(opaque_ty) => {
- let id: InternedOpaqueTyId = opaque_ty.opaque_ty_id.into();
- let def_id = SolverDefId::InternedOpaqueTyId(id);
- let alias_ty = rustc_type_ir::AliasTy::new_from_args(
- interner,
- def_id,
- opaque_ty.substitution.to_nextsolver(interner),
- );
- rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty)
- }
- },
- chalk_ir::TyKind::Function(fn_pointer) => {
- let sig_tys = fn_pointer.clone().into_binders(Interner).to_nextsolver(interner);
- let header = rustc_type_ir::FnHeader {
- abi: fn_pointer.sig.abi,
- c_variadic: fn_pointer.sig.variadic,
- safety: match fn_pointer.sig.safety {
- chalk_ir::Safety::Safe => super::abi::Safety::Safe,
- chalk_ir::Safety::Unsafe => super::abi::Safety::Unsafe,
- },
- };
-
- rustc_type_ir::TyKind::FnPtr(sig_tys, header)
- }
- // The schema here is quite confusing.
- // The new solver, like rustc, uses `Param` and `EarlyBinder` for generic params. It uses `BoundVar`
- // and `Placeholder` together with `Binder` for HRTB, which we mostly don't handle.
- // Chalk uses `Placeholder` for generic params and `BoundVar` quite liberally, and this is quite a
- // problem. `chalk_ir::TyKind::BoundVar` can represent either HRTB or generic params, depending on the
- // context. When returned from signature queries, the outer `Binders` represent the generic params.
- // But there are also inner `Binders` for HRTB.
- // AFAIK there is no way to tell which of the meanings is relevant, so we just use `rustc_type_ir::Bound`
- // here, and hope for the best. If you are working with new solver types, therefore, use the new solver
- // lower queries.
- // Hopefully sooner than later Chalk will be ripped from the codebase and we can avoid that problem.
- // For details about the rustc setup, read: https://rustc-dev-guide.rust-lang.org/generic_parameters_summary.html
- // and the following chapters.
- chalk_ir::TyKind::Placeholder(placeholder_index) => {
- let (id, index) = from_placeholder_idx(interner.db, *placeholder_index);
- rustc_type_ir::TyKind::Param(ParamTy {
- id: TypeParamId::from_unchecked(id),
- index,
- })
- }
- chalk_ir::TyKind::BoundVar(bound_var) => rustc_type_ir::TyKind::Bound(
- bound_var.debruijn.to_nextsolver(interner),
- BoundTy {
- var: rustc_type_ir::BoundVar::from_usize(bound_var.index),
- kind: BoundTyKind::Anon,
- },
- ),
- chalk_ir::TyKind::InferenceVar(inference_var, ty_variable_kind) => {
- rustc_type_ir::TyKind::Infer(
- (*inference_var, *ty_variable_kind).to_nextsolver(interner),
- )
- }
- },
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Ty<Interner>> for Ty<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Ty<Interner> {
- convert_ty_for_result(interner, self)
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Region<'db> {
- Region::new(
- interner,
- match self.data(Interner) {
- chalk_ir::LifetimeData::BoundVar(bound_var) => rustc_type_ir::RegionKind::ReBound(
- bound_var.debruijn.to_nextsolver(interner),
- BoundRegion {
- var: rustc_type_ir::BoundVar::from_u32(bound_var.index as u32),
- kind: BoundRegionKind::Anon,
- },
- ),
- chalk_ir::LifetimeData::InferenceVar(inference_var) => {
- rustc_type_ir::RegionKind::ReVar(rustc_type_ir::RegionVid::from_u32(
- inference_var.index(),
- ))
- }
- chalk_ir::LifetimeData::Placeholder(placeholder_index) => {
- let (id, index) = lt_from_placeholder_idx(interner.db, *placeholder_index);
- rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { id, index })
- }
- chalk_ir::LifetimeData::Static => rustc_type_ir::RegionKind::ReStatic,
- chalk_ir::LifetimeData::Erased => rustc_type_ir::RegionKind::ReErased,
- chalk_ir::LifetimeData::Phantom(_, _) => {
- unreachable!()
- }
- chalk_ir::LifetimeData::Error => {
- rustc_type_ir::RegionKind::ReError(ErrorGuaranteed)
- }
- },
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Lifetime<Interner>> for Region<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Lifetime<Interner> {
- convert_region_for_result(interner, self)
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Const<'db> {
- let data = self.data(Interner);
- Const::new(
- interner,
- match &data.value {
- chalk_ir::ConstValue::BoundVar(bound_var) => rustc_type_ir::ConstKind::Bound(
- bound_var.debruijn.to_nextsolver(interner),
- BoundConst { var: rustc_type_ir::BoundVar::from_usize(bound_var.index) },
- ),
- chalk_ir::ConstValue::InferenceVar(inference_var) => {
- rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(
- rustc_type_ir::ConstVid::from_u32(inference_var.index()),
- ))
- }
- chalk_ir::ConstValue::Placeholder(placeholder_index) => {
- let (id, index) = from_placeholder_idx(interner.db, *placeholder_index);
- rustc_type_ir::ConstKind::Param(ParamConst {
- id: ConstParamId::from_unchecked(id),
- index,
- })
- }
- chalk_ir::ConstValue::Concrete(concrete_const) => match &concrete_const.interned {
- ConstScalar::Bytes(bytes, memory) => {
- rustc_type_ir::ConstKind::Value(ValueConst::new(
- data.ty.to_nextsolver(interner),
- ConstBytes { memory: bytes.clone(), memory_map: memory.clone() },
- ))
- }
- ConstScalar::UnevaluatedConst(c, subst) => {
- let def = match *c {
- GeneralConstId::ConstId(id) => SolverDefId::ConstId(id),
- GeneralConstId::StaticId(id) => SolverDefId::StaticId(id),
- };
- let args = subst.to_nextsolver(interner);
- rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(def, args))
- }
- ConstScalar::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
- },
- },
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Const<Interner>> for Const<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Const<Interner> {
- convert_const_for_result(interner, self)
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>
- for chalk_ir::FnSubst<Interner>
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::FnSigTys<DbInterner<'db>> {
- rustc_type_ir::FnSigTys {
- inputs_and_output: Tys::new_from_iter(
- interner,
- self.0.iter(Interner).map(|g| g.assert_ty_ref(Interner).to_nextsolver(interner)),
- ),
- }
- }
-}
-
-impl<
- 'db,
- U: TypeVisitable<DbInterner<'db>>,
- T: Clone + ChalkToNextSolver<'db, U> + HasInterner<Interner = Interner>,
-> ChalkToNextSolver<'db, rustc_type_ir::Binder<DbInterner<'db>, U>> for chalk_ir::Binders<T>
-{
- fn to_nextsolver(
- &self,
- interner: DbInterner<'db>,
- ) -> rustc_type_ir::Binder<DbInterner<'db>, U> {
- let (val, binders) = self.clone().into_value_and_skipped_binders();
- rustc_type_ir::Binder::bind_with_vars(
- val.to_nextsolver(interner),
- binders.to_nextsolver(interner),
- )
- }
-}
-
-impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
- NextSolverToChalk<'db, chalk_ir::Binders<U>> for rustc_type_ir::Binder<DbInterner<'db>, T>
-{
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders<U> {
- chalk_ir::Binders::new(
- self.bound_vars().to_chalk(interner),
- self.skip_binder().to_chalk(interner),
- )
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds {
- BoundVarKinds::new_from_iter(
- interner,
- self.iter(Interner).map(|v| v.to_nextsolver(interner)),
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds<Interner> {
- chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner)))
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind {
- match self {
- chalk_ir::VariableKind::Ty(_ty_variable_kind) => BoundVarKind::Ty(BoundTyKind::Anon),
- chalk_ir::VariableKind::Lifetime => BoundVarKind::Region(BoundRegionKind::Anon),
- chalk_ir::VariableKind::Const(_ty) => BoundVarKind::Const,
- }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKind<Interner>> for BoundVarKind {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind<Interner> {
- match self {
- BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
- BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime,
- BoundVarKind::Const => {
- chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner))
- }
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> {
- match self.data(Interner) {
- chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner).into(),
- chalk_ir::GenericArgData::Lifetime(lifetime) => lifetime.to_nextsolver(interner).into(),
- chalk_ir::GenericArgData::Const(const_) => const_.to_nextsolver(interner).into(),
- }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::GenericArg> for GenericArg<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> crate::GenericArg {
- match self {
- GenericArg::Ty(ty) => ty.to_chalk(interner).cast(Interner),
- GenericArg::Lifetime(region) => region.to_chalk(interner).cast(Interner),
- GenericArg::Const(konst) => konst.to_chalk(interner).cast(Interner),
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> {
- GenericArgs::new_from_iter(
- interner,
- self.iter(Interner).map(|arg| -> GenericArg<'db> { arg.to_nextsolver(interner) }),
- )
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, crate::lower_nextsolver::ImplTraitIdx<'db>>
- for crate::ImplTraitIdx
-{
- fn to_nextsolver(
- &self,
- interner: DbInterner<'db>,
- ) -> crate::lower_nextsolver::ImplTraitIdx<'db> {
- crate::lower_nextsolver::ImplTraitIdx::from_raw(self.into_raw())
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Substitution<Interner>> for GenericArgs<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Substitution<Interner> {
- convert_args_for_result(interner, self.as_slice())
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Tys<'db> {
- Tys::new_from_iter(
- interner,
- self.iter(Interner).map(|arg| -> Ty<'db> {
- match arg.data(Interner) {
- chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner),
- chalk_ir::GenericArgData::Lifetime(_) => unreachable!(),
- chalk_ir::GenericArgData::Const(_) => unreachable!(),
- }
- }),
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::Substitution> for Tys<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> crate::Substitution {
- Substitution::from_iter(
- Interner,
- self.inner().iter().map(|ty| ty.to_chalk(interner).cast(Interner)),
- )
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex {
- fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex {
- rustc_type_ir::DebruijnIndex::from_u32(self.depth())
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::DebruijnIndex> for rustc_type_ir::DebruijnIndex {
- fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::DebruijnIndex {
- chalk_ir::DebruijnIndex::new(self.index() as u32)
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex {
- fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex {
- rustc_type_ir::UniverseIndex::from_u32(self.counter as u32)
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::UniverseIndex> for rustc_type_ir::UniverseIndex {
- fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::UniverseIndex {
- chalk_ir::UniverseIndex { counter: self.index() }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy>
- for (chalk_ir::InferenceVar, chalk_ir::TyVariableKind)
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::InferTy {
- match self.1 {
- chalk_ir::TyVariableKind::General => {
- rustc_type_ir::InferTy::TyVar(rustc_type_ir::TyVid::from_u32(self.0.index()))
- }
- chalk_ir::TyVariableKind::Integer => {
- rustc_type_ir::InferTy::IntVar(rustc_type_ir::IntVid::from_u32(self.0.index()))
- }
- chalk_ir::TyVariableKind::Float => {
- rustc_type_ir::InferTy::FloatVar(rustc_type_ir::FloatVid::from_u32(self.0.index()))
- }
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_ast_ir::Mutability {
- match self {
- chalk_ir::Mutability::Mut => rustc_ast_ir::Mutability::Mut,
- chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not,
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
- match self {
- crate::Variance::Covariant => rustc_type_ir::Variance::Covariant,
- crate::Variance::Invariant => rustc_type_ir::Variance::Invariant,
- crate::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
- crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant,
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
- match self {
- chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant,
- chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant,
- chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf {
- VariancesOf::new_from_iter(
- interner,
- self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)),
- )
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Goal<DbInterner<'db>, Predicate<'db>>>
- for chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Goal<DbInterner<'db>, Predicate<'db>> {
- Goal::new(
- interner,
- self.environment.to_nextsolver(interner),
- self.goal.to_nextsolver(interner),
- )
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>
- for Goal<DbInterner<'db>, Predicate<'db>>
-{
- fn to_chalk(
- self,
- interner: DbInterner<'db>,
- ) -> chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> {
- chalk_ir::InEnvironment {
- environment: self.param_env.to_chalk(interner),
- goal: self.predicate.to_chalk(interner),
- }
- }
-}
-
-impl<'db, T: HasInterner<Interner = Interner> + ChalkToNextSolver<'db, U>, U>
- ChalkToNextSolver<'db, Canonical<'db, U>> for chalk_ir::Canonical<T>
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Canonical<'db, U> {
- let variables = CanonicalVars::new_from_iter(
- interner,
- self.binders.iter(Interner).map(|k| match &k.kind {
- chalk_ir::VariableKind::Ty(ty_variable_kind) => match ty_variable_kind {
- // FIXME(next-solver): the info is incorrect, but we have no way to store the information in Chalk.
- TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty {
- ui: UniverseIndex::ROOT,
- sub_root: BoundVar::from_u32(0),
- },
- TyVariableKind::Integer => rustc_type_ir::CanonicalVarKind::Int,
- TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Float,
- },
- chalk_ir::VariableKind::Lifetime => {
- rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ROOT)
- }
- chalk_ir::VariableKind::Const(ty) => {
- rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ROOT)
- }
- }),
- );
- Canonical {
- max_universe: UniverseIndex::ROOT,
- value: self.value.to_nextsolver(interner),
- variables,
- }
- }
-}
-
-impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
- NextSolverToChalk<'db, chalk_ir::Canonical<U>> for Canonical<'db, T>
-{
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Canonical<U> {
- let binders = chalk_ir::CanonicalVarKinds::from_iter(
- Interner,
- self.variables.iter().map(|v| match v {
- rustc_type_ir::CanonicalVarKind::Ty { ui, sub_root: _ } => {
- chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Ty(TyVariableKind::General),
- chalk_ir::UniverseIndex { counter: ui.as_usize() },
- )
- }
- rustc_type_ir::CanonicalVarKind::Int => chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Ty(TyVariableKind::Integer),
- chalk_ir::UniverseIndex::root(),
- ),
- rustc_type_ir::CanonicalVarKind::Float => chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Ty(TyVariableKind::Float),
- chalk_ir::UniverseIndex::root(),
- ),
- rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Lifetime,
- chalk_ir::UniverseIndex { counter: ui.as_usize() },
- ),
- rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)),
- chalk_ir::UniverseIndex { counter: ui.as_usize() },
- ),
- rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(),
- rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(),
- rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(),
- }),
- );
- let value = self.value.to_chalk(interner);
- chalk_ir::Canonical { binders, value }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Predicate<'db> {
- match self.data(Interner) {
- chalk_ir::GoalData::Quantified(quantifier_kind, binders) => {
- if !binders.binders.is_empty(Interner) {
- panic!("Should not be constructed.");
- }
- let (val, _) = binders.clone().into_value_and_skipped_binders();
- val.shifted_out(Interner).unwrap().to_nextsolver(interner)
- }
- chalk_ir::GoalData::Implies(program_clauses, goal) => {
- panic!("Should not be constructed.")
- }
- chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."),
- chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."),
- chalk_ir::GoalData::EqGoal(eq_goal) => {
- let arg_to_term = |g: &chalk_ir::GenericArg<Interner>| match g.data(Interner) {
- chalk_ir::GenericArgData::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)),
- chalk_ir::GenericArgData::Const(const_) => {
- Term::Const(const_.to_nextsolver(interner))
- }
- chalk_ir::GenericArgData::Lifetime(lifetime) => unreachable!(),
- };
- let pred_kind = PredicateKind::AliasRelate(
- arg_to_term(&eq_goal.a),
- arg_to_term(&eq_goal.b),
- rustc_type_ir::AliasRelationDirection::Equate,
- );
- let pred_kind =
- Binder::bind_with_vars(pred_kind, BoundVarKinds::new_from_iter(interner, []));
- Predicate::new(interner, pred_kind)
- }
- chalk_ir::GoalData::SubtypeGoal(subtype_goal) => {
- let subtype_predicate = SubtypePredicate {
- a: subtype_goal.a.to_nextsolver(interner),
- b: subtype_goal.b.to_nextsolver(interner),
- a_is_expected: true,
- };
- let pred_kind = PredicateKind::Subtype(subtype_predicate);
- let pred_kind = Binder::bind_with_vars(
- shift_vars(interner, pred_kind, 1),
- BoundVarKinds::new_from_iter(interner, []),
- );
- Predicate::new(interner, pred_kind)
- }
- chalk_ir::GoalData::DomainGoal(domain_goal) => {
- let pred_kind = domain_goal.to_nextsolver(interner);
- let pred_kind = Binder::bind_with_vars(
- shift_vars(interner, pred_kind, 1),
- BoundVarKinds::new_from_iter(interner, []),
- );
- Predicate::new(interner, pred_kind)
- }
- chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."),
- }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Goal<Interner>> for Predicate<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Goal<Interner> {
- chalk_ir::Goal::new(Interner, self.kind().skip_binder().to_chalk(interner))
- }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::ProjectionTy> for crate::next_solver::AliasTy<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> crate::ProjectionTy {
- let SolverDefId::TypeAliasId(assoc_id) = self.def_id else { unreachable!() };
- crate::ProjectionTy {
- associated_ty_id: to_assoc_type_id(assoc_id),
- substitution: self.args.to_chalk(interner),
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> ParamEnv<'db> {
- let clauses = Clauses::new_from_iter(
- interner,
- self.clauses.iter(Interner).map(|c| c.to_nextsolver(interner)),
- );
- let clauses =
- Clauses::new_from_iter(interner, elaborate::elaborate(interner, clauses.iter()));
- ParamEnv { clauses }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Environment<Interner>> for ParamEnv<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Environment<Interner> {
- let clauses = chalk_ir::ProgramClauses::from_iter(
- Interner,
- self.clauses.iter().filter_map(|c| -> Option<chalk_ir::ProgramClause<Interner>> {
- c.to_chalk(interner)
- }),
- );
- chalk_ir::Environment { clauses }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> {
- Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner)))
- }
-}
-
-impl<'db> NextSolverToChalk<'db, Option<chalk_ir::ProgramClause<Interner>>> for Clause<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> Option<chalk_ir::ProgramClause<Interner>> {
- let value: chalk_ir::ProgramClauseImplication<Interner> =
- <PredicateKind<'db> as NextSolverToChalk<
- 'db,
- Option<chalk_ir::ProgramClauseImplication<Interner>>,
- >>::to_chalk(self.0.kind().skip_binder(), interner)?;
- Some(chalk_ir::ProgramClause::new(
- Interner,
- chalk_ir::ProgramClauseData(chalk_ir::Binders::empty(Interner, value)),
- ))
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>>
- for chalk_ir::ProgramClauseImplication<Interner>
-{
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
- assert!(self.conditions.is_empty(Interner));
- assert!(self.constraints.is_empty(Interner));
- self.consequence.to_nextsolver(interner)
- }
-}
-
-impl<'db> NextSolverToChalk<'db, Option<chalk_ir::ProgramClauseImplication<Interner>>>
- for PredicateKind<'db>
-{
- fn to_chalk(
- self,
- interner: DbInterner<'db>,
- ) -> Option<chalk_ir::ProgramClauseImplication<Interner>> {
- let chalk_ir::GoalData::DomainGoal(consequence) = self.to_chalk(interner) else {
- return None;
- };
-
- Some(chalk_ir::ProgramClauseImplication {
- consequence,
- conditions: chalk_ir::Goals::empty(Interner),
- constraints: chalk_ir::Constraints::empty(Interner),
- priority: chalk_ir::ClausePriority::High,
- })
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
- match self {
- chalk_ir::DomainGoal::Holds(where_clause) => match where_clause {
- chalk_ir::WhereClause::Implemented(trait_ref) => {
- let predicate = TraitPredicate {
- trait_ref: trait_ref.to_nextsolver(interner),
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- };
- PredicateKind::Clause(ClauseKind::Trait(predicate))
- }
- chalk_ir::WhereClause::AliasEq(alias_eq) => match &alias_eq.alias {
- chalk_ir::AliasTy::Projection(p) => {
- let def_id =
- SolverDefId::TypeAliasId(from_assoc_type_id(p.associated_ty_id));
- let args = p.substitution.to_nextsolver(interner);
- let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
- let term: Term<'db> = term.into();
- let predicate = ProjectionPredicate {
- projection_term: AliasTerm::new_from_args(interner, def_id, args),
- term,
- };
- PredicateKind::Clause(ClauseKind::Projection(predicate))
- }
- chalk_ir::AliasTy::Opaque(opaque) => {
- let id: InternedOpaqueTyId = opaque.opaque_ty_id.into();
- let def_id = SolverDefId::InternedOpaqueTyId(id);
- let args = opaque.substitution.to_nextsolver(interner);
- let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
- let term: Term<'db> = term.into();
- let opaque_ty = Ty::new(
- interner,
- rustc_type_ir::TyKind::Alias(
- rustc_type_ir::AliasTyKind::Opaque,
- rustc_type_ir::AliasTy::new_from_args(interner, def_id, args),
- ),
- )
- .into();
- PredicateKind::AliasRelate(
- opaque_ty,
- term,
- rustc_type_ir::AliasRelationDirection::Equate,
- )
- }
- },
- chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
- let predicate = OutlivesPredicate(
- lifetime_outlives.a.to_nextsolver(interner),
- lifetime_outlives.b.to_nextsolver(interner),
- );
- PredicateKind::Clause(ClauseKind::RegionOutlives(predicate))
- }
- chalk_ir::WhereClause::TypeOutlives(type_outlives) => {
- let predicate = OutlivesPredicate(
- type_outlives.ty.to_nextsolver(interner),
- type_outlives.lifetime.to_nextsolver(interner),
- );
- PredicateKind::Clause(ClauseKind::TypeOutlives(predicate))
- }
- },
- chalk_ir::DomainGoal::Normalize(normalize) => {
- let proj_ty = match &normalize.alias {
- chalk_ir::AliasTy::Projection(proj) => proj,
- _ => unimplemented!(),
- };
- let args: GenericArgs<'db> = proj_ty.substitution.to_nextsolver(interner);
- let alias = Ty::new(
- interner,
- rustc_type_ir::TyKind::Alias(
- rustc_type_ir::AliasTyKind::Projection,
- rustc_type_ir::AliasTy::new(
- interner,
- from_assoc_type_id(proj_ty.associated_ty_id).into(),
- args,
- ),
- ),
- )
- .into();
- let term = normalize.ty.to_nextsolver(interner).into();
- PredicateKind::AliasRelate(
- alias,
- term,
- rustc_type_ir::AliasRelationDirection::Equate,
- )
- }
- chalk_ir::DomainGoal::WellFormed(well_formed) => {
- let term = match well_formed {
- WellFormed::Trait(_) => panic!("Should not be constructed."),
- WellFormed::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)),
- };
- PredicateKind::Clause(rustc_type_ir::ClauseKind::WellFormed(term))
- }
- chalk_ir::DomainGoal::FromEnv(from_env) => match from_env {
- chalk_ir::FromEnv::Trait(trait_ref) => {
- let predicate = TraitPredicate {
- trait_ref: trait_ref.to_nextsolver(interner),
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- };
- PredicateKind::Clause(ClauseKind::Trait(predicate))
- }
- chalk_ir::FromEnv::Ty(ty) => PredicateKind::Clause(ClauseKind::WellFormed(
- Term::Ty(ty.to_nextsolver(interner)),
- )),
- },
- chalk_ir::DomainGoal::IsLocal(ty) => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::IsUpstream(ty) => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::IsFullyVisible(ty) => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::LocalImplAllowed(trait_ref) => {
- panic!("Should not be constructed.")
- }
- chalk_ir::DomainGoal::Compatible => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::DownstreamType(ty) => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::Reveal => panic!("Should not be constructed."),
- chalk_ir::DomainGoal::ObjectSafe(trait_id) => panic!("Should not be constructed."),
- }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::GoalData<Interner>> for PredicateKind<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::GoalData<Interner> {
- match self {
- rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => {
- let trait_ref = trait_pred.trait_ref.to_chalk(interner);
- let where_clause = chalk_ir::WhereClause::Implemented(trait_ref);
- chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
- }
- rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection(
- proj_predicate,
- )) => {
- let associated_ty_id = match proj_predicate.def_id() {
- SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
- _ => unreachable!(),
- };
- let substitution = proj_predicate.projection_term.args.to_chalk(interner);
- let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
- associated_ty_id,
- substitution,
- });
- let ty = match proj_predicate.term.kind() {
- rustc_type_ir::TermKind::Ty(ty) => ty,
- rustc_type_ir::TermKind::Const(_) => unimplemented!(),
- };
- let ty = ty.to_chalk(interner);
- let alias_eq = chalk_ir::AliasEq { alias, ty };
- let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq);
- chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
- }
- rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives(
- outlives,
- )) => {
- let lifetime = outlives.1.to_chalk(interner);
- let ty = outlives.0.to_chalk(interner);
- let where_clause =
- chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty });
- chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
- }
- rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives(
- outlives,
- )) => {
- let a = outlives.0.to_chalk(interner);
- let b = outlives.1.to_chalk(interner);
- let where_clause =
- chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b });
- chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
- }
- rustc_type_ir::PredicateKind::AliasRelate(
- alias_term,
- target_term,
- alias_relation_direction,
- ) => {
- let term_to_generic_arg = |term: Term<'db>| match term {
- Term::Ty(ty) => chalk_ir::GenericArg::new(
- Interner,
- chalk_ir::GenericArgData::Ty(ty.to_chalk(interner)),
- ),
- Term::Const(const_) => chalk_ir::GenericArg::new(
- Interner,
- chalk_ir::GenericArgData::Const(const_.to_chalk(interner)),
- ),
- };
-
- chalk_ir::GoalData::EqGoal(chalk_ir::EqGoal {
- a: term_to_generic_arg(alias_term),
- b: term_to_generic_arg(target_term),
- })
- }
- rustc_type_ir::PredicateKind::Clause(_) => unimplemented!(),
- rustc_type_ir::PredicateKind::DynCompatible(_) => unimplemented!(),
- rustc_type_ir::PredicateKind::Subtype(_) => unimplemented!(),
- rustc_type_ir::PredicateKind::Coerce(_) => unimplemented!(),
- rustc_type_ir::PredicateKind::ConstEquate(_, _) => unimplemented!(),
- rustc_type_ir::PredicateKind::Ambiguous => unimplemented!(),
- rustc_type_ir::PredicateKind::NormalizesTo(_) => unimplemented!(),
- }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> TraitRef<'db> {
- let args = self.substitution.to_nextsolver(interner);
- TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args)
- }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::TraitRef<Interner>> for TraitRef<'db> {
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::TraitRef<Interner> {
- let trait_id = to_chalk_trait_id(self.def_id.0);
- let substitution = self.args.to_chalk(interner);
- chalk_ir::TraitRef { trait_id, substitution }
- }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause<Interner> {
- fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
- match self {
- chalk_ir::WhereClause::Implemented(trait_ref) => {
- let predicate = TraitPredicate {
- trait_ref: trait_ref.to_nextsolver(interner),
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- };
- PredicateKind::Clause(ClauseKind::Trait(predicate))
- }
- chalk_ir::WhereClause::AliasEq(alias_eq) => {
- let projection = match &alias_eq.alias {
- chalk_ir::AliasTy::Projection(p) => p,
- _ => unimplemented!(),
- };
- let def_id =
- SolverDefId::TypeAliasId(from_assoc_type_id(projection.associated_ty_id));
- let args = projection.substitution.to_nextsolver(interner);
- let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
- let term: Term<'db> = term.into();
- let predicate = ProjectionPredicate {
- projection_term: AliasTerm::new_from_args(interner, def_id, args),
- term,
- };
- PredicateKind::Clause(ClauseKind::Projection(predicate))
- }
- chalk_ir::WhereClause::TypeOutlives(type_outlives) => {
- let ty = type_outlives.ty.to_nextsolver(interner);
- let r = type_outlives.lifetime.to_nextsolver(interner);
- PredicateKind::Clause(ClauseKind::TypeOutlives(OutlivesPredicate(ty, r)))
- }
- chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
- let a = lifetime_outlives.a.to_nextsolver(interner);
- let b = lifetime_outlives.b.to_nextsolver(interner);
- PredicateKind::Clause(ClauseKind::RegionOutlives(OutlivesPredicate(a, b)))
- }
- }
- }
-}
-
-impl<'db, I> NextSolverToChalk<'db, chalk_ir::ConstrainedSubst<Interner>> for I
-where
- I: IntoIterator<Item = GenericArg<'db>>,
-{
- fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::ConstrainedSubst<Interner> {
- chalk_ir::ConstrainedSubst {
- constraints: chalk_ir::Constraints::empty(Interner),
- subst: GenericArgs::new_from_iter(interner, self).to_chalk(interner),
- }
- }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig<DbInterner<'db>> {
- fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig {
- crate::CallableSig {
- abi: self.abi,
- is_varargs: self.c_variadic,
- safety: match self.safety {
- super::abi::Safety::Safe => chalk_ir::Safety::Safe,
- super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
- },
- params_and_return: triomphe::Arc::from_iter(
- self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)),
- ),
- }
- }
-}
-
-pub fn convert_canonical_args_for_result<'db>(
- interner: DbInterner<'db>,
- args: Canonical<'db, Vec<GenericArg<'db>>>,
-) -> chalk_ir::Canonical<chalk_ir::ConstrainedSubst<Interner>> {
- args.to_chalk(interner)
-}
-
-pub fn convert_args_for_result<'db>(
- interner: DbInterner<'db>,
- args: &[GenericArg<'db>],
-) -> crate::Substitution {
- let mut substs = Vec::with_capacity(args.len());
- for arg in args {
- match (*arg).kind() {
- rustc_type_ir::GenericArgKind::Type(ty) => {
- let ty = convert_ty_for_result(interner, ty);
- substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner));
- }
- rustc_type_ir::GenericArgKind::Lifetime(region) => {
- let lifetime = convert_region_for_result(interner, region);
- substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner));
- }
- rustc_type_ir::GenericArgKind::Const(const_) => {
- substs.push(
- chalk_ir::GenericArgData::Const(convert_const_for_result(interner, const_))
- .intern(Interner),
- );
- }
- }
- }
- Substitution::from_iter(Interner, substs)
-}
-
-pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
- use crate::{Scalar, TyKind};
- use chalk_ir::{FloatTy, IntTy, UintTy};
- match ty.kind() {
- rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool),
- rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char),
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => {
- TyKind::Scalar(Scalar::Int(IntTy::I8))
- }
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => {
- TyKind::Scalar(Scalar::Int(IntTy::I16))
- }
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => {
- TyKind::Scalar(Scalar::Int(IntTy::I32))
- }
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => {
- TyKind::Scalar(Scalar::Int(IntTy::I64))
- }
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => {
- TyKind::Scalar(Scalar::Int(IntTy::I128))
- }
- rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => {
- TyKind::Scalar(Scalar::Int(IntTy::Isize))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => {
- TyKind::Scalar(Scalar::Uint(UintTy::U8))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => {
- TyKind::Scalar(Scalar::Uint(UintTy::U16))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => {
- TyKind::Scalar(Scalar::Uint(UintTy::U32))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => {
- TyKind::Scalar(Scalar::Uint(UintTy::U64))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => {
- TyKind::Scalar(Scalar::Uint(UintTy::U128))
- }
- rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => {
- TyKind::Scalar(Scalar::Uint(UintTy::Usize))
- }
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => {
- TyKind::Scalar(Scalar::Float(FloatTy::F16))
- }
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => {
- TyKind::Scalar(Scalar::Float(FloatTy::F32))
- }
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => {
- TyKind::Scalar(Scalar::Float(FloatTy::F64))
- }
- rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => {
- TyKind::Scalar(Scalar::Float(FloatTy::F128))
- }
- rustc_type_ir::TyKind::Str => TyKind::Str,
- rustc_type_ir::TyKind::Error(_) => TyKind::Error,
- rustc_type_ir::TyKind::Never => TyKind::Never,
-
- rustc_type_ir::TyKind::Adt(def, args) => {
- let adt_id = def.inner().id;
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::Adt(chalk_ir::AdtId(adt_id), subst)
- }
-
- rustc_type_ir::TyKind::Infer(infer_ty) => {
- let (var, kind) = match infer_ty {
- rustc_type_ir::InferTy::TyVar(var) => {
- (InferenceVar::from(var.as_u32()), TyVariableKind::General)
- }
- rustc_type_ir::InferTy::IntVar(var) => {
- (InferenceVar::from(var.as_u32()), TyVariableKind::Integer)
- }
- rustc_type_ir::InferTy::FloatVar(var) => {
- (InferenceVar::from(var.as_u32()), TyVariableKind::Float)
- }
- rustc_type_ir::InferTy::FreshFloatTy(..)
- | rustc_type_ir::InferTy::FreshIntTy(..)
- | rustc_type_ir::InferTy::FreshTy(..) => {
- panic!("Freshening shouldn't happen.")
- }
- };
- TyKind::InferenceVar(var, kind)
- }
-
- rustc_type_ir::TyKind::Ref(r, ty, mutability) => {
- let mutability = match mutability {
- rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
- rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
- };
- let r = convert_region_for_result(interner, r);
- let ty = convert_ty_for_result(interner, ty);
- TyKind::Ref(mutability, r, ty)
- }
-
- rustc_type_ir::TyKind::Tuple(tys) => {
- let size = tys.len();
- let subst = Substitution::from_iter(
- Interner,
- tys.iter().map(|ty| {
- chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty))
- .intern(Interner)
- }),
- );
- TyKind::Tuple(size, subst)
- }
-
- rustc_type_ir::TyKind::Array(ty, const_) => {
- let ty = convert_ty_for_result(interner, ty);
- let const_ = convert_const_for_result(interner, const_);
- TyKind::Array(ty, const_)
- }
-
- rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind {
- rustc_type_ir::AliasTyKind::Projection => {
- let assoc_ty_id = match alias_ty.def_id {
- SolverDefId::TypeAliasId(id) => id,
- _ => unreachable!(),
- };
- let associated_ty_id = to_assoc_type_id(assoc_ty_id);
- let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
- TyKind::Alias(crate::AliasTy::Projection(crate::ProjectionTy {
- associated_ty_id,
- substitution,
- }))
- }
- rustc_type_ir::AliasTyKind::Opaque => {
- let opaque_ty_id = match alias_ty.def_id {
- SolverDefId::InternedOpaqueTyId(id) => id,
- _ => unreachable!(),
- };
- let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
- TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
- opaque_ty_id: opaque_ty_id.into(),
- substitution,
- }))
- }
- rustc_type_ir::AliasTyKind::Inherent => unimplemented!(),
- rustc_type_ir::AliasTyKind::Free => unimplemented!(),
- },
-
- // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion.
- rustc_type_ir::TyKind::Placeholder(placeholder) => {
- unimplemented!(
- "A `rustc_type_ir::TyKind::Placeholder` doesn't have a direct \
- correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
- It therefore feels safer to leave it panicking, but if you hit this panic \
- feel free to do the same as in `rustc_type_ir::TyKind::Bound` here."
- )
- }
- rustc_type_ir::TyKind::Bound(debruijn_index, ty) => TyKind::BoundVar(chalk_ir::BoundVar {
- debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
- index: ty.var.as_usize(),
- }),
- rustc_type_ir::TyKind::Param(param) => {
- let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index);
- TyKind::Placeholder(placeholder)
- }
-
- rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => {
- let num_binders = bound_sig.bound_vars().len();
- let sig = chalk_ir::FnSig {
- abi: fn_header.abi,
- safety: match fn_header.safety {
- crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
- crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
- },
- variadic: fn_header.c_variadic,
- };
- let args = GenericArgs::new_from_iter(
- interner,
- bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()),
- );
- let substitution = convert_args_for_result(interner, args.as_slice());
- let substitution = chalk_ir::FnSubst(substitution);
- let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution };
- TyKind::Function(fnptr)
- }
-
- rustc_type_ir::TyKind::Dynamic(preds, region) => {
- let self_ty = Ty::new_bound(
- interner,
- DebruijnIndex::from_u32(1),
- BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) },
- );
- let bounds = chalk_ir::QuantifiedWhereClauses::from_iter(
- Interner,
- preds.iter().map(|p| {
- let binders = chalk_ir::VariableKinds::from_iter(
- Interner,
- p.bound_vars().iter().map(|b| match b {
- BoundVarKind::Ty(kind) => {
- chalk_ir::VariableKind::Ty(TyVariableKind::General)
- }
- BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime,
- BoundVarKind::Const => {
- chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner))
- }
- }),
- );
-
- // Rust and chalk have slightly different
- // representation for trait objects.
- //
- // Chalk uses `for<T0> for<'a> T0: Trait<'a>` while rustc
- // uses `ExistentialPredicate`s, which do not have a self ty.
- // We need to shift escaping bound vars by 1 to accommodate
- // the newly introduced `for<T0>` binder.
- let p = shift_vars(interner, p, 1);
-
- let where_clause = match p.skip_binder() {
- rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
- let trait_ref = TraitRef::new(
- interner,
- trait_ref.def_id,
- [self_ty.into()].into_iter().chain(trait_ref.args.iter()),
- );
- let trait_id = to_chalk_trait_id(trait_ref.def_id.0);
- let substitution =
- convert_args_for_result(interner, trait_ref.args.as_slice());
- let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
- chalk_ir::WhereClause::Implemented(trait_ref)
- }
- rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => {
- let trait_id = to_chalk_trait_id(trait_.0);
- let substitution = chalk_ir::Substitution::from1(
- Interner,
- convert_ty_for_result(interner, self_ty),
- );
- let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
- chalk_ir::WhereClause::Implemented(trait_ref)
- }
- rustc_type_ir::ExistentialPredicate::Projection(existential_projection) => {
- let projection = ProjectionPredicate {
- projection_term: AliasTerm::new(
- interner,
- existential_projection.def_id,
- [self_ty.into()]
- .iter()
- .chain(existential_projection.args.iter()),
- ),
- term: existential_projection.term,
- };
- let associated_ty_id = match projection.projection_term.def_id {
- SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
- _ => unreachable!(),
- };
- let substitution = convert_args_for_result(
- interner,
- projection.projection_term.args.as_slice(),
- );
- let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
- associated_ty_id,
- substitution,
- });
- let ty = match projection.term {
- Term::Ty(ty) => ty,
- _ => unreachable!(),
- };
- let ty = convert_ty_for_result(interner, ty);
- let alias_eq = chalk_ir::AliasEq { alias, ty };
- chalk_ir::WhereClause::AliasEq(alias_eq)
- }
- };
- chalk_ir::Binders::new(binders, where_clause)
- }),
- );
- let binders = chalk_ir::VariableKinds::from1(
- Interner,
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
- );
- let bounds = chalk_ir::Binders::new(binders, bounds);
- let dyn_ty =
- chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(interner, region) };
- TyKind::Dyn(dyn_ty)
- }
-
- rustc_type_ir::TyKind::Slice(ty) => {
- let ty = convert_ty_for_result(interner, ty);
- TyKind::Slice(ty)
- }
-
- rustc_type_ir::TyKind::Foreign(foreign) => TyKind::Foreign(to_foreign_def_id(foreign.0)),
- rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(),
- rustc_type_ir::TyKind::RawPtr(ty, mutability) => {
- let mutability = match mutability {
- rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
- rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
- };
- let ty = convert_ty_for_result(interner, ty);
- TyKind::Raw(mutability, ty)
- }
- rustc_type_ir::TyKind::FnDef(def_id, args) => {
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::FnDef(def_id.0.to_chalk(interner.db()), subst)
- }
-
- rustc_type_ir::TyKind::Closure(def_id, args) => {
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::Closure(def_id.0.into(), subst)
- }
- rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(),
- rustc_type_ir::TyKind::Coroutine(def_id, args) => {
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::Coroutine(def_id.0.into(), subst)
- }
- rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => {
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::CoroutineWitness(def_id.0.into(), subst)
- }
-
- rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(),
- }
- .intern(Interner)
-}
-
-pub fn convert_const_for_result<'db>(
- interner: DbInterner<'db>,
- const_: Const<'db>,
-) -> crate::Const {
- let value: chalk_ir::ConstValue<Interner> = match const_.kind() {
- rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => {
- chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32()))
- }
- rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => {
- panic!("Vars should not be freshened.")
- }
- rustc_type_ir::ConstKind::Param(param) => {
- let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index);
- chalk_ir::ConstValue::Placeholder(placeholder)
- }
- rustc_type_ir::ConstKind::Bound(debruijn_index, var) => {
- chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
- chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
- var.var.index(),
- ))
- }
- rustc_type_ir::ConstKind::Placeholder(placeholder_const) => {
- unimplemented!(
- "A `rustc_type_ir::ConstKind::Placeholder` doesn't have a direct \
- correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
- It therefore feels safer to leave it panicking, but if you hit this panic \
- feel free to do the same as in `rustc_type_ir::ConstKind::Bound` here."
- )
- }
- rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => {
- let id = match unevaluated_const.def {
- SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
- SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
- _ => unreachable!(),
- };
- let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice());
- chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
- interned: ConstScalar::UnevaluatedConst(id, subst),
- })
- }
- rustc_type_ir::ConstKind::Value(value_const) => {
- let bytes = value_const.value.inner();
- let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
- // SAFETY: we will never actually use this without a database
- interned: ConstScalar::Bytes(bytes.memory.clone(), unsafe {
- std::mem::transmute::<MemoryMap<'db>, MemoryMap<'static>>(
- bytes.memory_map.clone(),
- )
- }),
- });
- return chalk_ir::ConstData {
- ty: convert_ty_for_result(interner, value_const.ty),
- value,
- }
- .intern(Interner);
- }
- rustc_type_ir::ConstKind::Error(_) => {
- chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
- interned: ConstScalar::Unknown,
- })
- }
- rustc_type_ir::ConstKind::Expr(_) => unimplemented!(),
- };
- chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner)
-}
-
-pub fn convert_region_for_result<'db>(
- interner: DbInterner<'db>,
- region: Region<'db>,
-) -> crate::Lifetime {
- let lifetime = match region.kind() {
- rustc_type_ir::RegionKind::ReEarlyParam(early) => {
- let placeholder = lt_to_placeholder_idx(interner.db, early.id, early.index);
- chalk_ir::LifetimeData::Placeholder(placeholder)
- }
- rustc_type_ir::RegionKind::ReBound(db, bound) => {
- chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
- chalk_ir::DebruijnIndex::new(db.as_u32()),
- bound.var.as_usize(),
- ))
- }
- rustc_type_ir::RegionKind::RePlaceholder(placeholder) => unimplemented!(
- "A `rustc_type_ir::RegionKind::RePlaceholder` doesn't have a direct \
- correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
- It therefore feels safer to leave it panicking, but if you hit this panic \
- feel free to do the same as in `rustc_type_ir::RegionKind::ReBound` here."
- ),
- rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(),
- rustc_type_ir::RegionKind::ReStatic => chalk_ir::LifetimeData::Static,
- rustc_type_ir::RegionKind::ReVar(vid) => {
- chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32()))
- }
- rustc_type_ir::RegionKind::ReErased => chalk_ir::LifetimeData::Erased,
- rustc_type_ir::RegionKind::ReError(_) => chalk_ir::LifetimeData::Error,
- };
- chalk_ir::Lifetime::new(Interner, lifetime)
-}
-
-pub trait InferenceVarExt {
- fn to_vid(self) -> rustc_type_ir::TyVid;
- fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar;
-}
-
-impl InferenceVarExt for InferenceVar {
- fn to_vid(self) -> rustc_type_ir::TyVid {
- rustc_type_ir::TyVid::from_u32(self.index())
- }
- fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar {
- InferenceVar::from(vid.as_u32())
- }
-}
diff --git a/crates/hir-ty/src/next_solver/normalize.rs b/crates/hir-ty/src/next_solver/normalize.rs
index 2f241f8..bd678b3 100644
--- a/crates/hir-ty/src/next_solver/normalize.rs
+++ b/crates/hir-ty/src/next_solver/normalize.rs
@@ -5,7 +5,6 @@
inherent::{IntoKind, Term as _},
};
-use crate::next_solver::SolverDefId;
use crate::next_solver::{
Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Term, Ty,
TyKind,
diff --git a/crates/hir-ty/src/next_solver/obligation_ctxt.rs b/crates/hir-ty/src/next_solver/obligation_ctxt.rs
index e85574a..ae92aea 100644
--- a/crates/hir-ty/src/next_solver/obligation_ctxt.rs
+++ b/crates/hir-ty/src/next_solver/obligation_ctxt.rs
@@ -1,14 +1,15 @@
use hir_def::TraitId;
-use rustc_type_ir::relate::Relate;
use rustc_type_ir::{TypeFoldable, Upcast, Variance};
-use crate::next_solver::fulfill::{FulfillmentCtxt, NextSolverError};
-use crate::next_solver::infer::at::ToTrace;
-use crate::next_solver::infer::traits::{
- Obligation, ObligationCause, PredicateObligation, PredicateObligations,
+use crate::next_solver::{
+ Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError,
+ fulfill::{FulfillmentCtxt, NextSolverError},
+ infer::{
+ InferCtxt, InferOk,
+ at::ToTrace,
+ traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations},
+ },
};
-use crate::next_solver::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace};
-use crate::next_solver::{Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError};
/// Used if you want to have pleasant experience when dealing
/// with obligations outside of hir or mir typeck.
@@ -69,21 +70,7 @@
) -> Result<(), TypeError<'db>> {
self.infcx
.at(cause, param_env)
- .eq(DefineOpaqueTypes::Yes, expected, actual)
- .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
- }
-
- pub fn eq_trace<T: Relate<DbInterner<'db>>>(
- &mut self,
- cause: &ObligationCause,
- param_env: ParamEnv<'db>,
- trace: TypeTrace<'db>,
- expected: T,
- actual: T,
- ) -> Result<(), TypeError<'db>> {
- self.infcx
- .at(cause, param_env)
- .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
+ .eq(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -97,7 +84,7 @@
) -> Result<(), TypeError<'db>> {
self.infcx
.at(cause, param_env)
- .sub(DefineOpaqueTypes::Yes, expected, actual)
+ .sub(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -111,7 +98,7 @@
) -> Result<(), TypeError<'db>> {
self.infcx
.at(cause, param_env)
- .relate(DefineOpaqueTypes::Yes, expected, variance, actual)
+ .relate(expected, variance, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -125,7 +112,7 @@
) -> Result<(), TypeError<'db>> {
self.infcx
.at(cause, param_env)
- .sup(DefineOpaqueTypes::Yes, expected, actual)
+ .sup(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
diff --git a/crates/hir-ty/src/next_solver/opaques.rs b/crates/hir-ty/src/next_solver/opaques.rs
index 0aee779..e8f5be2 100644
--- a/crates/hir-ty/src/next_solver/opaques.rs
+++ b/crates/hir-ty/src/next_solver/opaques.rs
@@ -1,86 +1,18 @@
//! Things related to opaques in the next-trait-solver.
-use intern::Interned;
use rustc_ast_ir::try_visit;
+use rustc_type_ir::inherent::SliceLike;
-use crate::next_solver::SolverDefId;
-
-use super::{CanonicalVarKind, DbInterner, interned_vec_nolifetime_salsa};
+use super::{DbInterner, SolverDefId, Ty, interned_vec_db, interned_vec_nolifetime_salsa};
pub type OpaqueTypeKey<'db> = rustc_type_ir::OpaqueTypeKey<DbInterner<'db>>;
-pub type PredefinedOpaquesData<'db> = rustc_type_ir::solve::PredefinedOpaquesData<DbInterner<'db>>;
+
+type PredefinedOpaque<'db> = (OpaqueTypeKey<'db>, Ty<'db>);
+interned_vec_db!(PredefinedOpaques, PredefinedOpaque);
+
pub type ExternalConstraintsData<'db> =
rustc_type_ir::solve::ExternalConstraintsData<DbInterner<'db>>;
-#[salsa::interned(constructor = new_, debug)]
-pub struct PredefinedOpaques<'db> {
- #[returns(ref)]
- kind_: rustc_type_ir::solve::PredefinedOpaquesData<DbInterner<'db>>,
-}
-
-impl<'db> PredefinedOpaques<'db> {
- pub fn new(interner: DbInterner<'db>, data: PredefinedOpaquesData<'db>) -> Self {
- PredefinedOpaques::new_(interner.db(), data)
- }
-
- pub fn inner(&self) -> &PredefinedOpaquesData<'db> {
- crate::with_attached_db(|db| {
- let inner = self.kind_(db);
- // SAFETY: ¯\_(ツ)_/¯
- unsafe { std::mem::transmute(inner) }
- })
- }
-}
-
-impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for PredefinedOpaques<'db> {
- fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
- &self,
- visitor: &mut V,
- ) -> V::Result {
- self.opaque_types.visit_with(visitor)
- }
-}
-
-impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for PredefinedOpaques<'db> {
- fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(PredefinedOpaques::new(
- folder.cx(),
- PredefinedOpaquesData {
- opaque_types: self
- .opaque_types
- .iter()
- .cloned()
- .map(|opaque| opaque.try_fold_with(folder))
- .collect::<Result<_, F::Error>>()?,
- },
- ))
- }
- fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
- PredefinedOpaques::new(
- folder.cx(),
- PredefinedOpaquesData {
- opaque_types: self
- .opaque_types
- .iter()
- .cloned()
- .map(|opaque| opaque.fold_with(folder))
- .collect(),
- },
- )
- }
-}
-
-impl<'db> std::ops::Deref for PredefinedOpaques<'db> {
- type Target = PredefinedOpaquesData<'db>;
-
- fn deref(&self) -> &Self::Target {
- self.inner()
- }
-}
-
interned_vec_nolifetime_salsa!(SolverDefIds, SolverDefId);
#[salsa::interned(constructor = new_, debug)]
diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs
index 9dda9d0..3438b75 100644
--- a/crates/hir-ty/src/next_solver/predicate.rs
+++ b/crates/hir-ty/src/next_solver/predicate.rs
@@ -2,21 +2,18 @@
use std::cmp::Ordering;
-use intern::Interned;
use macros::{TypeFoldable, TypeVisitable};
-use rustc_ast_ir::try_visit;
use rustc_type_ir::{
self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags,
PredicatePolarity, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
- TypeVisitable, Upcast, UpcastFrom, VisitorResult, WithCachedTypeInfo,
+ TypeVisitable, Upcast, UpcastFrom, WithCachedTypeInfo,
elaborate::Elaboratable,
error::{ExpectedFound, TypeError},
inherent::{IntoKind, SliceLike},
- relate::Relate,
};
-use smallvec::{SmallVec, smallvec};
+use smallvec::SmallVec;
-use crate::next_solver::TraitIdWrapper;
+use crate::next_solver::{InternedWrapperNoDebug, TraitIdWrapper};
use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db};
@@ -56,11 +53,11 @@
// FIXME: this is actual unstable - see impl in predicate.rs in `rustc_middle`
match (a, b) {
(ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal,
- (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => {
+ (ExistentialPredicate::Projection(_a), ExistentialPredicate::Projection(_b)) => {
// Should sort by def path hash
Ordering::Equal
}
- (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) => {
+ (ExistentialPredicate::AutoTrait(_a), ExistentialPredicate::AutoTrait(_b)) => {
// Should sort by def path hash
Ordering::Equal
}
@@ -174,9 +171,6 @@
}
}
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapperNoDebug<T>(pub(crate) T);
-
#[salsa::interned(constructor = new_)]
pub struct Predicate<'db> {
#[returns(ref)]
@@ -283,8 +277,6 @@
}
}
-type InternedClauses<'db> = Interned<InternedClausesWrapper<'db>>;
-
#[salsa::interned(constructor = new_)]
pub struct Clauses<'db> {
#[returns(ref)]
@@ -647,6 +639,26 @@
PredicateKind::Clause(ClauseKind::RegionOutlives(from)).upcast(interner)
}
}
+impl<'db> UpcastFrom<DbInterner<'db>, ty::OutlivesPredicate<DbInterner<'db>, Ty<'db>>>
+ for Clause<'db>
+{
+ fn upcast_from(
+ from: ty::OutlivesPredicate<DbInterner<'db>, Ty<'db>>,
+ interner: DbInterner<'db>,
+ ) -> Self {
+ Clause(from.upcast(interner))
+ }
+}
+impl<'db> UpcastFrom<DbInterner<'db>, ty::OutlivesPredicate<DbInterner<'db>, Region<'db>>>
+ for Clause<'db>
+{
+ fn upcast_from(
+ from: ty::OutlivesPredicate<DbInterner<'db>, Region<'db>>,
+ interner: DbInterner<'db>,
+ ) -> Self {
+ Clause(from.upcast(interner))
+ }
+}
impl<'db> UpcastFrom<DbInterner<'db>, PolyRegionOutlivesPredicate<'db>> for Predicate<'db> {
fn upcast_from(from: PolyRegionOutlivesPredicate<'db>, tcx: DbInterner<'db>) -> Self {
diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs
index 5e7eb75..b5f0e6d 100644
--- a/crates/hir-ty/src/next_solver/region.rs
+++ b/crates/hir-ty/src/next_solver/region.rs
@@ -1,10 +1,10 @@
//! Things related to regions.
use hir_def::LifetimeParamId;
-use intern::{Interned, Symbol};
+use intern::Symbol;
use rustc_type_ir::{
- BoundVar, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable,
- VisitorResult,
+ BoundVar, BoundVarIndexKind, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags,
+ TypeFoldable, TypeVisitable,
inherent::{IntoKind, PlaceholderLike, SliceLike},
relate::Relate,
};
@@ -68,7 +68,7 @@
index: DebruijnIndex,
bound: BoundRegion,
) -> Region<'db> {
- Region::new(interner, RegionKind::ReBound(index, bound))
+ Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound))
}
pub fn is_placeholder(&self) -> bool {
@@ -117,7 +117,11 @@
RegionKind::ReStatic => {
flags |= TypeFlags::HAS_FREE_REGIONS;
}
- RegionKind::ReBound(..) => {
+ RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
+ flags |= TypeFlags::HAS_RE_BOUND;
+ flags |= TypeFlags::HAS_CANONICAL_BOUND;
+ }
+ RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => {
flags |= TypeFlags::HAS_RE_BOUND;
}
RegionKind::ReErased => {
@@ -294,7 +298,7 @@
fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
match &self.inner() {
- RegionKind::ReBound(debruijn, _) => debruijn.shifted_in(1),
+ RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
_ => INNERMOST,
}
}
@@ -306,7 +310,7 @@
debruijn: rustc_type_ir::DebruijnIndex,
var: BoundRegion,
) -> Self {
- Region::new(interner, RegionKind::ReBound(debruijn, var))
+ Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), var))
}
fn new_anon_bound(
@@ -316,7 +320,20 @@
) -> Self {
Region::new(
interner,
- RegionKind::ReBound(debruijn, BoundRegion { var, kind: BoundRegionKind::Anon }),
+ RegionKind::ReBound(
+ BoundVarIndexKind::Bound(debruijn),
+ BoundRegion { var, kind: BoundRegionKind::Anon },
+ ),
+ )
+ }
+
+ fn new_canonical_bound(interner: DbInterner<'db>, var: rustc_type_ir::BoundVar) -> Self {
+ Region::new(
+ interner,
+ RegionKind::ReBound(
+ BoundVarIndexKind::Canonical,
+ BoundRegion { var, kind: BoundRegionKind::Anon },
+ ),
)
}
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 2457447..487d164 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -1,29 +1,22 @@
//! Defining `SolverContext` for next-trait-solver.
-use hir_def::{AssocItemId, GeneralConstId, TypeAliasId};
+use hir_def::{AssocItemId, GeneralConstId};
use rustc_next_trait_solver::delegate::SolverDelegate;
use rustc_type_ir::GenericArgKind;
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::{
- InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex,
- inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _},
+ InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt,
+ inherent::{IntoKind, Term as _, Ty as _},
solve::{Certainty, NoSolution},
};
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::next_solver::{CanonicalVarKind, ImplIdWrapper};
-use crate::{
- TraitRefExt,
- db::HirDatabase,
- next_solver::{
- ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, mapping::ChalkToNextSolver,
- util::sizedness_fast_path,
- },
+use crate::next_solver::{
+ ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, util::sizedness_fast_path,
};
use super::{
- Canonical, CanonicalVarValues, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
- ParamEnv, Predicate, SolverDefId, Span, Ty, UnevaluatedConst,
+ DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
};
@@ -66,7 +59,7 @@
(SolverContext(infcx), value, vars)
}
- fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> {
+ fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> {
match arg.kind() {
GenericArgKind::Lifetime(_) => self.next_region_var().into(),
GenericArgKind::Type(_) => self.next_ty_var().into(),
@@ -76,15 +69,15 @@
fn leak_check(
&self,
- max_input_universe: rustc_type_ir::UniverseIndex,
+ _max_input_universe: rustc_type_ir::UniverseIndex,
) -> Result<(), NoSolution> {
Ok(())
}
fn well_formed_goals(
&self,
- param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
- arg: <Self::Interner as rustc_type_ir::Interner>::Term,
+ _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+ _arg: <Self::Interner as rustc_type_ir::Interner>::Term,
) -> Option<
Vec<
rustc_type_ir::solve::Goal<
@@ -123,7 +116,7 @@
fn instantiate_canonical_var(
&self,
kind: CanonicalVarKind<'db>,
- span: <Self::Interner as Interner>::Span,
+ _span: <Self::Interner as Interner>::Span,
var_values: &[GenericArg<'db>],
universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex,
) -> GenericArg<'db> {
@@ -132,11 +125,11 @@
fn add_item_bounds_for_hidden_type(
&self,
- def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
- args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
- param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
- hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
- goals: &mut Vec<
+ _def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
+ _args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
+ _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+ _hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
+ _goals: &mut Vec<
rustc_type_ir::solve::Goal<
Self::Interner,
<Self::Interner as rustc_type_ir::Interner>::Predicate,
@@ -148,21 +141,10 @@
fn fetch_eligible_assoc_item(
&self,
- goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
+ _goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
trait_assoc_def_id: SolverDefId,
impl_id: ImplIdWrapper,
) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
- let trait_ = self
- .0
- .interner
- .db()
- .impl_trait(impl_id.0)
- // ImplIds for impls where the trait ref can't be resolved should never reach solver
- .expect("invalid impl passed to next-solver")
- .skip_binder()
- .def_id
- .0;
- let trait_data = trait_.trait_items(self.0.interner.db());
let impl_items = impl_id.0.impl_items(self.0.interner.db());
let id = match trait_assoc_def_id {
SolverDefId::TypeAliasId(trait_assoc_id) => {
@@ -208,16 +190,16 @@
fn is_transmutable(
&self,
- dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
- src: <Self::Interner as rustc_type_ir::Interner>::Ty,
- assume: <Self::Interner as rustc_type_ir::Interner>::Const,
+ _dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
+ _src: <Self::Interner as rustc_type_ir::Interner>::Ty,
+ _assume: <Self::Interner as rustc_type_ir::Interner>::Const,
) -> Result<Certainty, NoSolution> {
unimplemented!()
}
fn evaluate_const(
&self,
- param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+ _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
let c = match uv.def {
@@ -236,7 +218,7 @@
Self::Interner,
<Self::Interner as rustc_type_ir::Interner>::Predicate,
>,
- span: <Self::Interner as rustc_type_ir::Interner>::Span,
+ _span: <Self::Interner as rustc_type_ir::Interner>::Span,
) -> Option<Certainty> {
if let Some(trait_pred) = goal.predicate.as_trait_clause() {
if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
@@ -279,8 +261,8 @@
let pred = goal.predicate.kind();
match pred.no_bound_vars()? {
- PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => Some(Certainty::Yes),
- PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => Some(Certainty::Yes),
+ PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes),
+ PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes),
PredicateKind::Subtype(SubtypePredicate { a, b, .. })
| PredicateKind::Coerce(CoercePredicate { a, b }) => {
if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 44b85ab..b8406fe 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -1,41 +1,37 @@
//! Things related to tys in the next-trait-solver.
-use std::iter;
use std::ops::ControlFlow;
use hir_def::{
- AdtId, DefWithBodyId, GenericDefId, HasModule, TypeOrConstParamId, TypeParamId,
+ AdtId, HasModule, TypeParamId,
hir::generics::{TypeOrConstParamData, TypeParamProvenance},
lang_item::LangItem,
};
use hir_def::{TraitId, type_ref::Rawness};
-use intern::{Interned, Symbol, sym};
use rustc_abi::{Float, Integer, Size};
use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
use rustc_type_ir::{
- AliasTyKind, BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid,
- InferTy, IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
- TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
+ AliasTyKind, BoundVar, BoundVarIndexKind, ClosureKind, CoroutineArgs, CoroutineArgsParts,
+ DebruijnIndex, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, Interner,
+ TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
inherent::{
- Abi, AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _,
+ AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _,
IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _,
},
relate::Relate,
solve::SizedTraitKind,
walk::TypeWalker,
};
-use salsa::plumbing::{AsId, FromId};
-use smallvec::SmallVec;
use crate::{
- FnAbi, ImplTraitId,
- db::HirDatabase,
- interner::InternedWrapperNoDebug,
+ ImplTraitId,
+ db::{HirDatabase, InternedCoroutine},
next_solver::{
- AdtDef, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
+ AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper,
abi::Safety,
- mapping::ChalkToNextSolver,
+ interner::InternedWrapperNoDebug,
util::{CoroutineArgsExt, IntegerTypeExt},
},
};
@@ -83,7 +79,7 @@
Ty::new(interner, TyKind::Adt(AdtDef::new(adt_id, interner), args))
}
- pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> Self {
+ pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32) -> Self {
Ty::new(interner, TyKind::Param(ParamTy { id, index }))
}
@@ -404,10 +400,44 @@
Some(interner.fn_sig(callable).instantiate(interner, args))
}
TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)),
- TyKind::Closure(closure_id, closure_args) => closure_args
+ TyKind::Closure(_, closure_args) => closure_args
.split_closure_args_untupled()
.closure_sig_as_fn_ptr_ty
.callable_sig(interner),
+ TyKind::CoroutineClosure(coroutine_id, args) => {
+ Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
+ let unit_ty = Ty::new_unit(interner);
+ let return_ty = Ty::new_coroutine(
+ interner,
+ coroutine_id,
+ CoroutineArgs::new(
+ interner,
+ CoroutineArgsParts {
+ parent_args: args.as_coroutine_closure().parent_args(),
+ kind_ty: unit_ty,
+ resume_ty: unit_ty,
+ yield_ty: unit_ty,
+ return_ty: sig.return_ty,
+ // FIXME: Deduce this from the coroutine closure's upvars.
+ tupled_upvars_ty: unit_ty,
+ },
+ )
+ .args,
+ );
+ FnSig {
+ inputs_and_output: Tys::new_from_iter(
+ interner,
+ sig.tupled_inputs_ty
+ .tuple_fields()
+ .iter()
+ .chain(std::iter::once(return_ty)),
+ ),
+ c_variadic: sig.c_variadic,
+ safety: sig.safety,
+ abi: sig.abi,
+ }
+ }))
+ }
_ => None,
}
}
@@ -535,40 +565,21 @@
TyKind::Alias(AliasTyKind::Opaque, opaque_ty) => {
match db.lookup_intern_impl_trait_id(opaque_ty.def_id.expect_opaque_ty()) {
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
- db.return_type_impl_traits_ns(func).map(|it| {
- let data = (*it).as_ref().map_bound(|rpit| {
- &rpit.impl_traits[idx.to_nextsolver(interner)].predicates
- });
+ db.return_type_impl_traits(func).map(|it| {
+ let data =
+ (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
.collect()
})
}
ImplTraitId::TypeAliasImplTrait(alias, idx) => {
- db.type_alias_impl_traits_ns(alias).map(|it| {
- let data = (*it).as_ref().map_bound(|rpit| {
- &rpit.impl_traits[idx.to_nextsolver(interner)].predicates
- });
+ db.type_alias_impl_traits(alias).map(|it| {
+ let data =
+ (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
.collect()
})
}
- ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
- let krate = def.module(db).krate();
- if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
- // This is only used by type walking.
- // Parameters will be walked outside, and projection predicate is not used.
- // So just provide the Future trait.
- let impl_bound = TraitRef::new(
- interner,
- future_trait.into(),
- GenericArgs::new_from_iter(interner, []),
- )
- .upcast(interner);
- Some(vec![impl_bound])
- } else {
- None
- }
- }
}
}
TyKind::Param(param) => {
@@ -579,7 +590,7 @@
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::ArgumentImplTrait => {
let predicates = db
- .generic_predicates_ns(param.id.parent())
+ .generic_predicates(param.id.parent())
.instantiate_identity()
.into_iter()
.flatten()
@@ -598,6 +609,24 @@
_ => None,
}
}
+ TyKind::Coroutine(coroutine_id, _args) => {
+ let InternedCoroutine(owner, _) = coroutine_id.0.loc(db);
+ let krate = owner.module(db).krate();
+ if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
+ // This is only used by type walking.
+ // Parameters will be walked outside, and projection predicate is not used.
+ // So just provide the Future trait.
+ let impl_bound = TraitRef::new(
+ interner,
+ future_trait.into(),
+ GenericArgs::new_from_iter(interner, []),
+ )
+ .upcast(interner);
+ Some(vec![impl_bound])
+ } else {
+ None
+ }
+ }
_ => None,
}
}
@@ -899,27 +928,28 @@
Ty::new(interner, TyKind::Placeholder(param))
}
- fn new_bound(
- interner: DbInterner<'db>,
- debruijn: rustc_type_ir::DebruijnIndex,
- var: BoundTy,
- ) -> Self {
- Ty::new(interner, TyKind::Bound(debruijn, var))
+ fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundTy) -> Self {
+ Ty::new(interner, TyKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
}
- fn new_anon_bound(
- interner: DbInterner<'db>,
- debruijn: rustc_type_ir::DebruijnIndex,
- var: BoundVar,
- ) -> Self {
- Ty::new(interner, TyKind::Bound(debruijn, BoundTy { var, kind: BoundTyKind::Anon }))
+ fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
+ Ty::new(
+ interner,
+ TyKind::Bound(
+ BoundVarIndexKind::Bound(debruijn),
+ BoundTy { var, kind: BoundTyKind::Anon },
+ ),
+ )
}
- fn new_alias(
- interner: DbInterner<'db>,
- kind: rustc_type_ir::AliasTyKind,
- alias_ty: rustc_type_ir::AliasTy<DbInterner<'db>>,
- ) -> Self {
+ fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
+ Ty::new(
+ interner,
+ TyKind::Bound(BoundVarIndexKind::Canonical, BoundTy { var, kind: BoundTyKind::Anon }),
+ )
+ }
+
+ fn new_alias(interner: DbInterner<'db>, kind: AliasTyKind, alias_ty: AliasTy<'db>) -> Self {
Ty::new(interner, TyKind::Alias(kind, alias_ty))
}
@@ -929,7 +959,7 @@
fn new_adt(
interner: DbInterner<'db>,
- adt_def: <DbInterner<'db> as rustc_type_ir::Interner>::AdtDef,
+ adt_def: <DbInterner<'db> as Interner>::AdtDef,
args: GenericArgs<'db>,
) -> Self {
Ty::new(interner, TyKind::Adt(adt_def, args))
@@ -941,8 +971,8 @@
fn new_dynamic(
interner: DbInterner<'db>,
- preds: <DbInterner<'db> as rustc_type_ir::Interner>::BoundExistentialPredicates,
- region: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
+ preds: <DbInterner<'db> as Interner>::BoundExistentialPredicates,
+ region: <DbInterner<'db> as Interner>::Region,
) -> Self {
Ty::new(interner, TyKind::Dynamic(preds, region))
}
@@ -950,7 +980,7 @@
fn new_coroutine(
interner: DbInterner<'db>,
def_id: CoroutineIdWrapper,
- args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
Ty::new(interner, TyKind::Coroutine(def_id, args))
}
@@ -958,7 +988,7 @@
fn new_coroutine_closure(
interner: DbInterner<'db>,
def_id: CoroutineIdWrapper,
- args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
Ty::new(interner, TyKind::CoroutineClosure(def_id, args))
}
@@ -966,7 +996,7 @@
fn new_closure(
interner: DbInterner<'db>,
def_id: ClosureIdWrapper,
- args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
Ty::new(interner, TyKind::Closure(def_id, args))
}
@@ -974,7 +1004,7 @@
fn new_coroutine_witness(
interner: DbInterner<'db>,
def_id: CoroutineIdWrapper,
- args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
Ty::new(interner, TyKind::CoroutineWitness(def_id, args))
}
@@ -982,7 +1012,7 @@
fn new_coroutine_witness_for_coroutine(
interner: DbInterner<'db>,
def_id: CoroutineIdWrapper,
- coroutine_args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ coroutine_args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
// HACK: Coroutine witness types are lifetime erased, so they
// never reference any lifetime args from the coroutine. We erase
@@ -1010,7 +1040,7 @@
fn new_ref(
interner: DbInterner<'db>,
- region: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
+ region: <DbInterner<'db> as Interner>::Region,
ty: Self,
mutbl: rustc_ast_ir::Mutability,
) -> Self {
@@ -1020,7 +1050,7 @@
fn new_array_with_const_len(
interner: DbInterner<'db>,
ty: Self,
- len: <DbInterner<'db> as rustc_type_ir::Interner>::Const,
+ len: <DbInterner<'db> as Interner>::Const,
) -> Self {
Ty::new(interner, TyKind::Array(ty, len))
}
@@ -1029,10 +1059,7 @@
Ty::new(interner, TyKind::Slice(ty))
}
- fn new_tup(
- interner: DbInterner<'db>,
- tys: &[<DbInterner<'db> as rustc_type_ir::Interner>::Ty],
- ) -> Self {
+ fn new_tup(interner: DbInterner<'db>, tys: &[<DbInterner<'db> as Interner>::Ty]) -> Self {
Ty::new(interner, TyKind::Tuple(Tys::new_from_iter(interner, tys.iter().cloned())))
}
@@ -1047,7 +1074,7 @@
fn new_fn_def(
interner: DbInterner<'db>,
def_id: CallableIdWrapper,
- args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
) -> Self {
Ty::new(interner, TyKind::FnDef(def_id, args))
}
@@ -1063,12 +1090,19 @@
fn new_pat(
interner: DbInterner<'db>,
ty: Self,
- pat: <DbInterner<'db> as rustc_type_ir::Interner>::Pat,
+ pat: <DbInterner<'db> as Interner>::Pat,
) -> Self {
Ty::new(interner, TyKind::Pat(ty, pat))
}
- fn tuple_fields(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::Tys {
+ fn new_unsafe_binder(
+ interner: DbInterner<'db>,
+ ty: rustc_type_ir::Binder<DbInterner<'db>, <DbInterner<'db> as Interner>::Ty>,
+ ) -> Self {
+ Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
+ }
+
+ fn tuple_fields(self) -> <DbInterner<'db> as Interner>::Tys {
match self.kind() {
TyKind::Tuple(args) => args,
_ => panic!("tuple_fields called on non-tuple: {self:?}"),
@@ -1115,10 +1149,11 @@
}
}
- fn discriminant_ty(
- self,
- interner: DbInterner<'db>,
- ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
+ fn has_unsafe_fields(self) -> bool {
+ false
+ }
+
+ fn discriminant_ty(self, interner: DbInterner<'db>) -> <DbInterner<'db> as Interner>::Ty {
match self.kind() {
TyKind::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(interner),
TyKind::Coroutine(_, args) => args.as_coroutine().discr_ty(interner),
@@ -1172,20 +1207,6 @@
TyKind::UnsafeBinder(..) => unimplemented!(),
}
}
-
- fn new_unsafe_binder(
- interner: DbInterner<'db>,
- ty: rustc_type_ir::Binder<
- DbInterner<'db>,
- <DbInterner<'db> as rustc_type_ir::Interner>::Ty,
- >,
- ) -> Self {
- Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
- }
-
- fn has_unsafe_fields(self) -> bool {
- false
- }
}
interned_vec_db!(Tys, Ty);
@@ -1197,14 +1218,14 @@
}
impl<'db> rustc_type_ir::inherent::Tys<DbInterner<'db>> for Tys<'db> {
- fn inputs(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::FnInputTys {
+ fn inputs(self) -> <DbInterner<'db> as Interner>::FnInputTys {
Tys::new_from_iter(
DbInterner::conjure(),
self.as_slice().split_last().unwrap().1.iter().copied(),
)
}
- fn output(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
+ fn output(self) -> <DbInterner<'db> as Interner>::Ty {
*self.as_slice().split_last().unwrap().0
}
}
@@ -1222,7 +1243,7 @@
impl ParamTy {
pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> {
- Ty::new_param(interner, self.id, self.index, sym::MISSING_NAME.clone())
+ Ty::new_param(interner, self.id, self.index)
}
}
@@ -1269,11 +1290,11 @@
impl<'db> TypeFoldable<DbInterner<'db>> for ErrorGuaranteed {
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
self,
- folder: &mut F,
+ _folder: &mut F,
) -> Result<Self, F::Error> {
Ok(self)
}
- fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, _folder: &mut F) -> Self {
self
}
}
diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs
index ae240a9..d113f76 100644
--- a/crates/hir-ty/src/next_solver/util.rs
+++ b/crates/hir-ty/src/next_solver/util.rs
@@ -1,50 +1,40 @@
//! Various utilities for the next-trait-solver.
-use std::iter;
-use std::ops::{self, ControlFlow};
+use std::{
+ iter,
+ ops::{self, ControlFlow},
+};
use base_db::Crate;
-use hir_def::lang_item::LangItem;
-use hir_def::{BlockId, HasModule, ItemContainerId, Lookup};
-use intern::sym;
+use hir_def::{BlockId, HasModule, lang_item::LangItem};
use la_arena::Idx;
use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions};
-use rustc_type_ir::data_structures::IndexMap;
-use rustc_type_ir::inherent::{
- AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike,
- Ty as _,
-};
-use rustc_type_ir::lang_items::SolverTraitLangItem;
-use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::{
- BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity,
- TypeFlags, TypeVisitable, TypeVisitableExt,
+ ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner,
+ PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
+ TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex,
+ inherent::{
+ AdtDef, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Ty as _,
+ },
+ lang_items::SolverTraitLangItem,
+ solve::SizedTraitKind,
};
-use rustc_type_ir::{
- ConstKind, CoroutineArgs, FloatTy, IntTy, RegionKind, TypeFolder, TypeSuperFoldable,
- TypeSuperVisitable, TypeVisitor, UintTy, UniverseIndex, inherent::IntoKind,
-};
-use rustc_type_ir::{InferCtxtLike, TypeFoldable};
-use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext};
-use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::{
- BoundConst, CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst,
- PlaceholderRegion, TypingMode,
-};
use crate::{
db::HirDatabase,
- from_foreign_def_id,
+ lower::{LifetimeElisionKind, TyLoweringContext},
method_resolution::{TraitImpls, TyFingerprint},
+ next_solver::{
+ BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion,
+ infer::InferCtxt,
+ },
};
-use super::fold::{BoundVarReplacer, FnMutDelegate};
-use super::generics::generics;
use super::{
- AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds,
- CanonicalVars, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArg,
- GenericArgs, Predicate, PredicateKind, ProjectionPredicate, Region, SolverContext, SolverDefId,
- Term, TraitPredicate, TraitRef, Ty, TyKind,
+ Binder, BoundRegion, BoundTy, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder,
+ GenericArgs, Predicate, PredicateKind, Region, SolverDefId, TraitPredicate, TraitRef, Ty,
+ TyKind,
+ fold::{BoundVarReplacer, FnMutDelegate},
};
#[derive(Clone, Debug)]
@@ -514,151 +504,6 @@
b.skip_binder().fold_with(&mut instantiate)
}
-pub(crate) fn mini_canonicalize<'db, T: TypeFoldable<DbInterner<'db>>>(
- mut context: SolverContext<'db>,
- val: T,
-) -> Canonical<DbInterner<'db>, T> {
- let mut canon = MiniCanonicalizer {
- context: &mut context,
- db: DebruijnIndex::ZERO,
- vars: IndexMap::default(),
- };
- let canon_val = val.fold_with(&mut canon);
- let vars = canon.vars;
- Canonical {
- value: canon_val,
- max_universe: UniverseIndex::from_u32(1),
- variables: CanonicalVars::new_from_iter(
- context.cx(),
- vars.iter().enumerate().map(|(idx, (k, v))| match (*k).kind() {
- GenericArgKind::Type(ty) => match ty.kind() {
- TyKind::Int(..) | TyKind::Uint(..) => rustc_type_ir::CanonicalVarKind::Int,
- TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Float,
- _ => rustc_type_ir::CanonicalVarKind::Ty {
- ui: UniverseIndex::ZERO,
- sub_root: BoundVar::from_usize(idx),
- },
- },
- GenericArgKind::Lifetime(_) => {
- rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO)
- }
- GenericArgKind::Const(_) => {
- rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ZERO)
- }
- }),
- ),
- }
-}
-
-struct MiniCanonicalizer<'a, 'db> {
- context: &'a mut SolverContext<'db>,
- db: DebruijnIndex,
- vars: IndexMap<GenericArg<'db>, usize>,
-}
-
-impl<'db> TypeFolder<DbInterner<'db>> for MiniCanonicalizer<'_, 'db> {
- fn cx(&self) -> DbInterner<'db> {
- self.context.cx()
- }
-
- fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
- &mut self,
- t: rustc_type_ir::Binder<DbInterner<'db>, T>,
- ) -> rustc_type_ir::Binder<DbInterner<'db>, T> {
- self.db.shift_in(1);
- let res = t.map_bound(|t| t.fold_with(self));
- self.db.shift_out(1);
- res
- }
-
- fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
- match t.kind() {
- rustc_type_ir::TyKind::Bound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- t
- }
- rustc_type_ir::TyKind::Infer(infer) => {
- let t = match infer {
- rustc_type_ir::InferTy::TyVar(vid) => {
- self.context.opportunistic_resolve_ty_var(vid)
- }
- rustc_type_ir::InferTy::IntVar(vid) => {
- self.context.opportunistic_resolve_int_var(vid)
- }
- rustc_type_ir::InferTy::FloatVar(vid) => {
- self.context.opportunistic_resolve_float_var(vid)
- }
- _ => t,
- };
- let len = self.vars.len();
- let var = *self.vars.entry(t.into()).or_insert(len);
- Ty::new(
- self.cx(),
- TyKind::Bound(
- self.db,
- BoundTy { kind: super::BoundTyKind::Anon, var: BoundVar::from_usize(var) },
- ),
- )
- }
- _ => t.super_fold_with(self),
- }
- }
-
- fn fold_region(
- &mut self,
- r: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
- ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Region {
- match r.kind() {
- RegionKind::ReBound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- r
- }
- RegionKind::ReVar(vid) => {
- let len = self.vars.len();
- let var = *self.vars.entry(r.into()).or_insert(len);
- Region::new(
- self.cx(),
- RegionKind::ReBound(
- self.db,
- BoundRegion {
- kind: super::BoundRegionKind::Anon,
- var: BoundVar::from_usize(var),
- },
- ),
- )
- }
- _ => r,
- }
- }
-
- fn fold_const(
- &mut self,
- c: <DbInterner<'db> as rustc_type_ir::Interner>::Const,
- ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Const {
- match c.kind() {
- ConstKind::Bound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- c
- }
- ConstKind::Infer(infer) => {
- let len = self.vars.len();
- let var = *self.vars.entry(c.into()).or_insert(len);
- Const::new(
- self.cx(),
- ConstKind::Bound(self.db, BoundConst { var: BoundVar::from_usize(var) }),
- )
- }
- _ => c.super_fold_with(self),
- }
- }
-}
-
pub fn explicit_item_bounds<'db>(
interner: DbInterner<'db>,
def_id: SolverDefId,
@@ -666,14 +511,8 @@
let db = interner.db();
match def_id {
SolverDefId::TypeAliasId(type_alias) => {
- let trait_ = match type_alias.lookup(db).container {
- ItemContainerId::TraitId(t) => t,
- _ => panic!("associated type not in trait"),
- };
-
// Lower bounds -- we could/should maybe move this to a separate query in `lower`
let type_alias_data = db.type_alias_signature(type_alias);
- let generic_params = generics(db, type_alias.into());
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
let mut ctx = TyLoweringContext::new(
db,
@@ -723,7 +562,7 @@
match full_id {
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
let datas = db
- .return_type_impl_traits_ns(func)
+ .return_type_impl_traits(func)
.expect("impl trait id without impl traits");
let datas = (*datas).as_ref().skip_binder();
let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
@@ -731,104 +570,15 @@
}
crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = db
- .type_alias_impl_traits_ns(alias)
+ .type_alias_impl_traits(alias)
.expect("impl trait id without impl traits");
let datas = (*datas).as_ref().skip_binder();
let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone()))
}
- crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
- if let Some((future_trait, future_output)) = LangItem::Future
- .resolve_trait(db, interner.krate.expect("Must have interner.krate"))
- .and_then(|trait_| {
- let alias = trait_.trait_items(db).associated_type_by_name(
- &hir_expand::name::Name::new_symbol_root(sym::Output.clone()),
- )?;
- Some((trait_, alias))
- })
- {
- let args = GenericArgs::identity_for_item(interner, def_id);
- let out = args.as_slice()[0];
- let mut predicates = vec![];
-
- let item_ty = Ty::new_alias(
- interner,
- rustc_type_ir::AliasTyKind::Opaque,
- AliasTy::new_from_args(interner, def_id, args),
- );
-
- let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- trait_ref: TraitRef::new_from_args(
- interner,
- future_trait.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- let sized_trait = LangItem::Sized
- .resolve_trait(db, interner.krate.expect("Must have interner.krate"));
- if let Some(sized_trait_) = sized_trait {
- let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- trait_ref: TraitRef::new_from_args(
- interner,
- sized_trait_.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- }
- let kind =
- PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate {
- projection_term: AliasTerm::new_from_args(
- interner,
- future_output.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- term: match out.kind() {
- GenericArgKind::Lifetime(lt) => panic!(),
- GenericArgKind::Type(ty) => Term::Ty(ty),
- GenericArgKind::Const(const_) => Term::Const(const_),
- },
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- EarlyBinder::bind(Clauses::new_from_iter(interner, predicates))
- } else {
- // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
- EarlyBinder::bind(Clauses::new_from_iter(interner, []))
- }
- }
}
}
- _ => panic!("Unexpected GeneridDefId"),
+ _ => panic!("Unexpected GenericDefId"),
}
}
@@ -993,26 +743,6 @@
}
}
-pub(crate) fn needs_normalization<'db, T: TypeVisitable<DbInterner<'db>>>(
- infcx: &InferCtxt<'db>,
- value: &T,
-) -> bool {
- let mut flags = TypeFlags::HAS_ALIAS;
-
- // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
- // so we can ignore those.
- match infcx.typing_mode() {
- // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
- TypingMode::Coherence
- | TypingMode::Analysis { .. }
- | TypingMode::Borrowck { .. }
- | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(TypeFlags::HAS_TY_OPAQUE),
- TypingMode::PostAnalysis => {}
- }
-
- value.has_type_flags(flags)
-}
-
pub fn sizedness_fast_path<'db>(
tcx: DbInterner<'db>,
predicate: Predicate<'db>,
diff --git a/crates/hir-ty/src/primitive.rs b/crates/hir-ty/src/primitive.rs
index d2901f7..9ffb112 100644
--- a/crates/hir-ty/src/primitive.rs
+++ b/crates/hir-ty/src/primitive.rs
@@ -1,7 +1,7 @@
//! A few helper functions for dealing with primitives.
-pub use chalk_ir::{FloatTy, IntTy, UintTy};
pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint};
+pub use rustc_type_ir::{FloatTy, IntTy, UintTy};
pub fn int_ty_to_string(ty: IntTy) -> &'static str {
match ty {
@@ -33,68 +33,3 @@
FloatTy::F128 => "f128",
}
}
-
-pub fn int_ty_to_string_ns(ty: rustc_type_ir::IntTy) -> &'static str {
- use rustc_type_ir::IntTy;
- match ty {
- IntTy::Isize => "isize",
- IntTy::I8 => "i8",
- IntTy::I16 => "i16",
- IntTy::I32 => "i32",
- IntTy::I64 => "i64",
- IntTy::I128 => "i128",
- }
-}
-
-pub fn uint_ty_to_string_ns(ty: rustc_type_ir::UintTy) -> &'static str {
- use rustc_type_ir::UintTy;
- match ty {
- UintTy::Usize => "usize",
- UintTy::U8 => "u8",
- UintTy::U16 => "u16",
- UintTy::U32 => "u32",
- UintTy::U64 => "u64",
- UintTy::U128 => "u128",
- }
-}
-
-pub fn float_ty_to_string_ns(ty: rustc_type_ir::FloatTy) -> &'static str {
- use rustc_type_ir::FloatTy;
- match ty {
- FloatTy::F16 => "f16",
- FloatTy::F32 => "f32",
- FloatTy::F64 => "f64",
- FloatTy::F128 => "f128",
- }
-}
-
-pub(super) fn int_ty_from_builtin(t: BuiltinInt) -> IntTy {
- match t {
- BuiltinInt::Isize => IntTy::Isize,
- BuiltinInt::I8 => IntTy::I8,
- BuiltinInt::I16 => IntTy::I16,
- BuiltinInt::I32 => IntTy::I32,
- BuiltinInt::I64 => IntTy::I64,
- BuiltinInt::I128 => IntTy::I128,
- }
-}
-
-pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy {
- match t {
- BuiltinUint::Usize => UintTy::Usize,
- BuiltinUint::U8 => UintTy::U8,
- BuiltinUint::U16 => UintTy::U16,
- BuiltinUint::U32 => UintTy::U32,
- BuiltinUint::U64 => UintTy::U64,
- BuiltinUint::U128 => UintTy::U128,
- }
-}
-
-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,
- }
-}
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
new file mode 100644
index 0000000..611947b
--- /dev/null
+++ b/crates/hir-ty/src/specialization.rs
@@ -0,0 +1,150 @@
+//! Impl specialization related things
+
+use hir_def::{ImplId, nameres::crate_def_map};
+use intern::sym;
+use tracing::debug;
+
+use crate::{
+ db::HirDatabase,
+ next_solver::{
+ DbInterner, TypingMode,
+ infer::{
+ DbInternerInferExt,
+ traits::{Obligation, ObligationCause},
+ },
+ obligation_ctxt::ObligationCtxt,
+ },
+};
+
+// rustc does not have a cycle handling for the `specializes` query, meaning a cycle is a bug,
+// and indeed I was unable to cause cycles even with erroneous code. However, in r-a we can
+// create a cycle if there is an error in the impl's where clauses. I believe well formed code
+// cannot create a cycle, but a cycle handler is required nevertheless.
+fn specializes_cycle(
+ _db: &dyn HirDatabase,
+ _specializing_impl_def_id: ImplId,
+ _parent_impl_def_id: ImplId,
+) -> bool {
+ false
+}
+
+/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`?
+///
+/// For every type that could apply to `specializing_impl_def_id`, we prove that
+/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and
+/// its where-clauses hold).
+///
+/// For the purposes of const traits, we also check that the specializing
+/// impl is not more restrictive than the parent impl. That is, if the
+/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]`
+/// bounds), then `specializing_impl_def_id` must also be const for the same
+/// set of types.
+#[salsa::tracked(cycle_result = specializes_cycle)]
+pub(crate) fn specializes(
+ db: &dyn HirDatabase,
+ specializing_impl_def_id: ImplId,
+ parent_impl_def_id: ImplId,
+) -> bool {
+ let module = specializing_impl_def_id.loc(db).container;
+
+ // We check that the specializing impl comes from a crate that has specialization enabled.
+ //
+ // We don't really care if the specialized impl (the parent) is in a crate that has
+ // specialization enabled, since it's not being specialized.
+ //
+ // rustc also checks whether the specializing impls comes from a macro marked
+ // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]`
+ // is an internal feature, std is not using it for specialization nor is likely to
+ // ever use it, and we don't have the span information necessary to replicate that.
+ let def_map = crate_def_map(db, module.krate());
+ if !def_map.is_unstable_feature_enabled(&sym::specialization)
+ && !def_map.is_unstable_feature_enabled(&sym::min_specialization)
+ {
+ return false;
+ }
+
+ let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
+
+ let specializing_impl_signature = db.impl_signature(specializing_impl_def_id);
+ let parent_impl_signature = db.impl_signature(parent_impl_def_id);
+
+ // We determine whether there's a subset relationship by:
+ //
+ // - replacing bound vars with placeholders in impl1,
+ // - assuming the where clauses for impl1,
+ // - instantiating impl2 with fresh inference variables,
+ // - unifying,
+ // - attempting to prove the where clauses for impl2
+ //
+ // The last three steps are encapsulated in `fulfill_implication`.
+ //
+ // See RFC 1210 for more details and justification.
+
+ // Currently we do not allow e.g., a negative impl to specialize a positive one
+ if specializing_impl_signature.is_negative() != parent_impl_signature.is_negative() {
+ return false;
+ }
+
+ // create a parameter environment corresponding to an identity instantiation of the specializing impl,
+ // i.e. the most generic instantiation of the specializing impl.
+ let param_env = db.trait_environment(specializing_impl_def_id.into()).env;
+
+ // Create an infcx, taking the predicates of the specializing impl as assumptions:
+ let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+
+ let specializing_impl_trait_ref =
+ db.impl_trait(specializing_impl_def_id).unwrap().instantiate_identity();
+ let cause = &ObligationCause::dummy();
+ debug!(
+ "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+ param_env, specializing_impl_trait_ref, parent_impl_def_id
+ );
+
+ // Attempt to prove that the parent impl applies, given all of the above.
+
+ let mut ocx = ObligationCtxt::new(&infcx);
+
+ let parent_args = infcx.fresh_args_for_item(parent_impl_def_id.into());
+ let parent_impl_trait_ref = db
+ .impl_trait(parent_impl_def_id)
+ .expect("expected source impl to be a trait impl")
+ .instantiate(interner, parent_args);
+
+ // do the impls unify? If not, no specialization.
+ let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
+ else {
+ return false;
+ };
+
+ // Now check that the source trait ref satisfies all the where clauses of the target impl.
+ // This is not just for correctness; we also need this to constrain any params that may
+ // only be referenced via projection predicates.
+ if let Some(predicates) =
+ db.generic_predicates(parent_impl_def_id.into()).instantiate(interner, parent_args)
+ {
+ ocx.register_obligations(
+ predicates
+ .map(|predicate| Obligation::new(interner, cause.clone(), param_env, predicate)),
+ );
+ }
+
+ let errors = ocx.evaluate_obligations_error_on_ambiguity();
+ if !errors.is_empty() {
+ // no dice!
+ debug!(
+ "fulfill_implication: for impls on {:?} and {:?}, \
+ could not fulfill: {:?} given {:?}",
+ specializing_impl_trait_ref, parent_impl_trait_ref, errors, param_env
+ );
+ return false;
+ }
+
+ // FIXME: Check impl constness (when we implement const impls).
+
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ specializing_impl_trait_ref, parent_impl_trait_ref
+ );
+
+ true
+}
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 76cd5f7..bc47019 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -44,7 +44,7 @@
"body_shim",
"body_with_source_map_shim",
"trait_environment_shim",
- "return_type_impl_traits_ns_shim",
+ "return_type_impl_traits_shim",
"expr_scopes_shim",
"lang_item",
"crate_lang_items",
@@ -131,7 +131,7 @@
"body_shim",
"body_with_source_map_shim",
"trait_environment_shim",
- "return_type_impl_traits_ns_shim",
+ "return_type_impl_traits_shim",
"expr_scopes_shim",
"lang_item",
"crate_lang_items",
@@ -143,7 +143,7 @@
"body_shim",
"body_with_source_map_shim",
"trait_environment_shim",
- "return_type_impl_traits_ns_shim",
+ "return_type_impl_traits_shim",
"expr_scopes_shim",
"infer_shim",
"function_signature_shim",
@@ -151,7 +151,7 @@
"body_shim",
"body_with_source_map_shim",
"trait_environment_shim",
- "return_type_impl_traits_ns_shim",
+ "return_type_impl_traits_shim",
"expr_scopes_shim",
]
"#]],
@@ -585,8 +585,8 @@
"crate_lang_items",
"attrs_shim",
"attrs_shim",
- "generic_predicates_ns_shim",
- "return_type_impl_traits_ns_shim",
+ "generic_predicates_shim",
+ "return_type_impl_traits_shim",
"infer_shim",
"function_signature_shim",
"function_signature_with_source_map_shim",
@@ -594,7 +594,7 @@
"expr_scopes_shim",
"struct_signature_shim",
"struct_signature_with_source_map_shim",
- "generic_predicates_ns_shim",
+ "generic_predicates_shim",
"value_ty_shim",
"VariantFields::firewall_",
"VariantFields::query_",
@@ -608,9 +608,9 @@
"trait_impls_in_crate_shim",
"impl_trait_with_diagnostics_shim",
"impl_self_ty_with_diagnostics_shim",
- "generic_predicates_ns_shim",
+ "generic_predicates_shim",
"value_ty_shim",
- "generic_predicates_ns_shim",
+ "generic_predicates_shim",
]
"#]],
);
@@ -682,13 +682,13 @@
"attrs_shim",
"attrs_shim",
"attrs_shim",
- "generic_predicates_ns_shim",
- "return_type_impl_traits_ns_shim",
+ "generic_predicates_shim",
+ "return_type_impl_traits_shim",
"infer_shim",
"function_signature_with_source_map_shim",
"expr_scopes_shim",
"struct_signature_with_source_map_shim",
- "generic_predicates_ns_shim",
+ "generic_predicates_shim",
"VariantFields::query_",
"inherent_impls_in_crate_shim",
"impl_signature_with_source_map_shim",
@@ -697,8 +697,8 @@
"trait_impls_in_crate_shim",
"impl_trait_with_diagnostics_shim",
"impl_self_ty_with_diagnostics_shim",
- "generic_predicates_ns_shim",
- "generic_predicates_ns_shim",
+ "generic_predicates_shim",
+ "generic_predicates_shim",
]
"#]],
);
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index 5983ec7..f8b73cd 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -472,3 +472,55 @@
"#,
);
}
+
+#[test]
+fn regression_16282() {
+ check_infer(
+ r#"
+//- minicore: coerce_unsized, dispatch_from_dyn
+trait MapLookup<Q> {
+ type MapValue;
+}
+
+impl<K> MapLookup<K> for K {
+ type MapValue = K;
+}
+
+trait Map: MapLookup<<Self as Map>::Key> {
+ type Key;
+}
+
+impl<K> Map for K {
+ type Key = K;
+}
+
+
+fn main() {
+ let _ = &()
+ as &dyn Map<Key=u32,MapValue=u32>;
+}
+"#,
+ expect![[r#"
+ 210..272 '{ ...32>; }': ()
+ 220..221 '_': &'? (dyn Map<MapValue = u32, Key = u32> + '?)
+ 224..227 '&()': &'? ()
+ 224..269 '&() ...e=u32>': &'? (dyn Map<MapValue = u32, Key = u32> + 'static)
+ 225..227 '()': ()
+ "#]],
+ );
+}
+
+#[test]
+fn regression_18692() {
+ check_no_mismatches(
+ r#"
+//- minicore: coerce_unsized, dispatch_from_dyn, send
+trait Trait: Send {}
+
+fn f(_: *const (dyn Trait + Send)) {}
+fn g(it: *const (dyn Trait)) {
+ f(it);
+}
+"#,
+ );
+}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 38af7cb..c2392b3 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3856,9 +3856,9 @@
74..75 'f': F
80..82 '{}': ()
94..191 '{ ... }); }': ()
- 100..113 'async_closure': fn async_closure<impl FnOnce(i32)>(impl FnOnce(i32))
+ 100..113 'async_closure': fn async_closure<impl AsyncFnOnce(i32)>(impl AsyncFnOnce(i32))
100..147 'async_... })': ()
- 114..146 'async ... }': impl FnOnce(i32)
+ 114..146 'async ... }': impl AsyncFnOnce(i32)
121..124 'arg': i32
126..146 '{ ... }': ()
136..139 'arg': i32
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 0cf723e..f72ca22 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -85,7 +85,6 @@
}
#[test]
-#[ignore = "FIXME(next-solver): fix async closures"]
fn infer_async_closure() {
check_types(
r#"
@@ -93,7 +92,7 @@
async fn test() {
let f = async move |x: i32| x + 42;
f;
-// ^ impl Fn(i32) -> impl Future<Output = i32>
+// ^ impl AsyncFn(i32) -> i32
let a = f(4);
a;
// ^ impl Future<Output = i32>
@@ -102,7 +101,7 @@
// ^ i32
let f = async move || 42;
f;
-// ^ impl Fn() -> impl Future<Output = i32>
+// ^ impl AsyncFn() -> i32
let a = f();
a;
// ^ impl Future<Output = i32>
@@ -119,7 +118,7 @@
};
let _: Option<u64> = c().await;
c;
-// ^ impl Fn() -> impl Future<Output = Option<u64>>
+// ^ impl AsyncFn() -> Option<u64>
}
"#,
);
@@ -4930,7 +4929,6 @@
#[test]
fn async_fn_return_type() {
- // FIXME(next-solver): Async closures are lowered as closures currently. We should fix that.
check_infer(
r#"
//- minicore: async_fn
@@ -4948,9 +4946,9 @@
46..53 'loop {}': !
51..53 '{}': ()
67..97 '{ ...()); }': ()
- 73..76 'foo': fn foo<impl Fn(), ()>(impl Fn())
+ 73..76 'foo': fn foo<impl AsyncFn(), ()>(impl AsyncFn())
73..94 'foo(as...|| ())': ()
- 77..93 'async ... || ()': impl Fn()
+ 77..93 'async ... || ()': impl AsyncFn()
91..93 '()': ()
"#]],
);
diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs
deleted file mode 100644
index fe4cf7a..0000000
--- a/crates/hir-ty/src/tls.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-//! Implementation of Chalk debug helper functions using TLS.
-use std::fmt::{self, Display};
-
-use itertools::Itertools;
-use span::Edition;
-
-use crate::{
- CallableDefId, Interner, ProjectionTyExt, chalk_db, db::HirDatabase, from_assoc_type_id,
- from_chalk_trait_id, mapping::from_chalk,
-};
-use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
-
-#[allow(unused)]
-pub(crate) use unsafe_tls::{set_current_program, with_current_program};
-
-pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
-
-impl DebugContext<'_> {
- pub(crate) fn debug_struct_id(
- &self,
- id: chalk_db::AdtId,
- f: &mut fmt::Formatter<'_>,
- ) -> Result<(), fmt::Error> {
- let name = match id.0 {
- AdtId::StructId(it) => self.0.struct_signature(it).name.clone(),
- AdtId::UnionId(it) => self.0.union_signature(it).name.clone(),
- AdtId::EnumId(it) => self.0.enum_signature(it).name.clone(),
- };
- name.display(self.0, Edition::LATEST).fmt(f)?;
- Ok(())
- }
-
- pub(crate) fn debug_trait_id(
- &self,
- id: chalk_db::TraitId,
- f: &mut fmt::Formatter<'_>,
- ) -> Result<(), fmt::Error> {
- let trait_: hir_def::TraitId = from_chalk_trait_id(id);
- let trait_data = self.0.trait_signature(trait_);
- trait_data.name.display(self.0, Edition::LATEST).fmt(f)?;
- Ok(())
- }
-
- pub(crate) fn debug_assoc_type_id(
- &self,
- id: chalk_db::AssocTypeId,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Result<(), fmt::Error> {
- let type_alias: TypeAliasId = from_assoc_type_id(id);
- let type_alias_data = self.0.type_alias_signature(type_alias);
- let trait_ = match type_alias.lookup(self.0).container {
- ItemContainerId::TraitId(t) => t,
- _ => panic!("associated type not in trait"),
- };
- let trait_data = self.0.trait_signature(trait_);
- write!(
- fmt,
- "{}::{}",
- trait_data.name.display(self.0, Edition::LATEST),
- type_alias_data.name.display(self.0, Edition::LATEST)
- )?;
- Ok(())
- }
-
- pub(crate) fn debug_projection_ty(
- &self,
- projection_ty: &chalk_ir::ProjectionTy<Interner>,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Result<(), fmt::Error> {
- let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
- let type_alias_data = self.0.type_alias_signature(type_alias);
- let trait_ = match type_alias.lookup(self.0).container {
- ItemContainerId::TraitId(t) => t,
- _ => panic!("associated type not in trait"),
- };
- let trait_name = &self.0.trait_signature(trait_).name;
- let trait_ref = projection_ty.trait_ref(self.0);
- let trait_params = trait_ref.substitution.as_slice(Interner);
- let self_ty = trait_ref.self_type_parameter(Interner);
- write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0, Edition::LATEST))?;
- if trait_params.len() > 1 {
- write!(
- fmt,
- "<{}>",
- trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
- )?;
- }
- write!(fmt, ">::{}", type_alias_data.name.display(self.0, Edition::LATEST))?;
-
- let proj_params = &projection_ty.substitution.as_slice(Interner)[trait_params.len()..];
- if !proj_params.is_empty() {
- write!(
- fmt,
- "<{}>",
- proj_params.iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
- )?;
- }
-
- Ok(())
- }
-
- pub(crate) fn debug_fn_def_id(
- &self,
- fn_def_id: chalk_ir::FnDefId<Interner>,
- fmt: &mut fmt::Formatter<'_>,
- ) -> Result<(), fmt::Error> {
- let def: CallableDefId = from_chalk(self.0, fn_def_id);
- let name = match def {
- CallableDefId::FunctionId(ff) => self.0.function_signature(ff).name.clone(),
- CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(),
- CallableDefId::EnumVariantId(e) => {
- let loc = e.lookup(self.0);
- loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone()
- }
- };
- match def {
- CallableDefId::FunctionId(_) => {
- write!(fmt, "{{fn {}}}", name.display(self.0, Edition::LATEST))
- }
- CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
- write!(fmt, "{{ctor {}}}", name.display(self.0, Edition::LATEST))
- }
- }
- }
-}
-
-mod unsafe_tls {
- use super::DebugContext;
- use crate::db::HirDatabase;
- use scoped_tls::scoped_thread_local;
-
- scoped_thread_local!(static PROGRAM: DebugContext<'_>);
-
- pub(crate) fn with_current_program<R>(
- op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
- ) -> R {
- if PROGRAM.is_set() { PROGRAM.with(|prog| op(Some(prog))) } else { op(None) }
- }
-
- #[allow(dead_code)]
- pub(crate) fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
- where
- OP: FnOnce() -> R,
- {
- let ctx = DebugContext(p);
- // we're transmuting the lifetime in the DebugContext to static. This is
- // fine because we only keep the reference for the lifetime of this
- // function, *and* the only way to access the context is through
- // `with_current_program`, which hides the lifetime through the `for`
- // type.
- let static_p: &DebugContext<'static> =
- unsafe { std::mem::transmute::<&DebugContext<'_>, &DebugContext<'static>>(&ctx) };
- PROGRAM.set(static_p, op)
- }
-}
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index cd125f3..7f6d4ff 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -3,35 +3,26 @@
use core::fmt;
use std::hash::Hash;
-use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable};
-
use base_db::Crate;
use hir_def::{BlockId, TraitId, lang_item::LangItem};
use hir_expand::name::Name;
use intern::sym;
use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt};
use rustc_type_ir::{
- InferCtxtLike, TypingMode,
- inherent::{IntoKind, SliceLike, Span as _, Ty as _},
+ TypingMode,
+ inherent::{IntoKind, Span as _},
solve::Certainty,
};
-use span::Edition;
-use stdx::never;
use triomphe::Arc;
use crate::{
- AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
- ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause,
db::HirDatabase,
- from_assoc_type_id,
next_solver::{
- DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
+ Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span, Ty,
+ TyKind,
infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
- mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result},
obligation_ctxt::ObligationCtxt,
- util::mini_canonicalize,
},
- utils::UnevaluatedConstEvaluatorFolder,
};
/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -44,7 +35,7 @@
pub krate: Crate,
pub block: Option<BlockId>,
// FIXME make this a BTreeMap
- traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+ traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
pub env: ParamEnv<'db>,
}
@@ -61,7 +52,7 @@
pub fn new(
krate: Crate,
block: Option<BlockId>,
- traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+ traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
env: ParamEnv<'db>,
) -> Arc<Self> {
Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
@@ -72,10 +63,7 @@
Arc::make_mut(this).block = Some(block);
}
- pub fn traits_in_scope_from_clauses(
- &self,
- ty: crate::next_solver::Ty<'db>,
- ) -> impl Iterator<Item = TraitId> + '_ {
+ pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator<Item = TraitId> + '_ {
self.traits_from_clauses
.iter()
.filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id))
@@ -85,172 +73,19 @@
/// This should be used in `hir` only.
pub fn structurally_normalize_ty<'db>(
infcx: &InferCtxt<'db>,
- ty: crate::next_solver::Ty<'db>,
+ ty: Ty<'db>,
env: Arc<TraitEnvironment<'db>>,
-) -> crate::next_solver::Ty<'db> {
- let crate::next_solver::TyKind::Alias(..) = ty.kind() else { return ty };
+) -> Ty<'db> {
+ let TyKind::Alias(..) = ty.kind() else { return ty };
let mut ocx = ObligationCtxt::new(infcx);
let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty);
ty.replace_infer_with_error(infcx.interner)
}
-pub(crate) fn normalize_projection_query<'db>(
- db: &'db dyn HirDatabase,
- projection: ProjectionTy,
- env: Arc<TraitEnvironment<'db>>,
-) -> Ty {
- if projection.substitution.iter(Interner).any(|arg| {
- arg.ty(Interner)
- .is_some_and(|ty| ty.data(Interner).flags.intersects(TypeFlags::HAS_TY_INFER))
- }) {
- never!(
- "Invoking `normalize_projection_query` with a projection type containing inference var"
- );
- return TyKind::Error.intern(Interner);
- }
-
- let interner = DbInterner::new_with(db, Some(env.krate), env.block);
- // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things),
- // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT
- // and async blocks.
- let infcx = interner.infer_ctxt().build(TypingMode::Analysis {
- defining_opaque_types_and_generators: crate::next_solver::SolverDefIds::new_from_iter(
- interner,
- [],
- ),
- });
- let alias_ty = crate::next_solver::Ty::new_alias(
- interner,
- rustc_type_ir::AliasTyKind::Projection,
- crate::next_solver::AliasTy::new(
- interner,
- from_assoc_type_id(projection.associated_ty_id).into(),
- <crate::Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(&projection.substitution, interner),
- ),
- );
- let mut ctxt = crate::next_solver::obligation_ctxt::ObligationCtxt::new(&infcx);
- let normalized = ctxt
- .structurally_normalize_ty(&ObligationCause::dummy(), env.env, alias_ty)
- .unwrap_or(alias_ty);
- normalized.replace_infer_with_error(interner).to_chalk(interner)
-}
-
-fn identity_subst(
- binders: chalk_ir::CanonicalVarKinds<Interner>,
-) -> chalk_ir::Canonical<chalk_ir::Substitution<Interner>> {
- let identity_subst = chalk_ir::Substitution::from_iter(
- Interner,
- binders.iter(Interner).enumerate().map(|(index, c)| {
- let index_db = chalk_ir::BoundVar::new(DebruijnIndex::INNERMOST, index);
- match &c.kind {
- chalk_ir::VariableKind::Ty(_) => {
- chalk_ir::GenericArgData::Ty(TyKind::BoundVar(index_db).intern(Interner))
- .intern(Interner)
- }
- chalk_ir::VariableKind::Lifetime => chalk_ir::GenericArgData::Lifetime(
- chalk_ir::LifetimeData::BoundVar(index_db).intern(Interner),
- )
- .intern(Interner),
- chalk_ir::VariableKind::Const(ty) => chalk_ir::GenericArgData::Const(
- chalk_ir::ConstData {
- ty: ty.clone(),
- value: chalk_ir::ConstValue::BoundVar(index_db),
- }
- .intern(Interner),
- )
- .intern(Interner),
- }
- }),
- );
- chalk_ir::Canonical { binders, value: identity_subst }
-}
-
-/// Solve a trait goal using next trait solver.
-pub(crate) fn trait_solve_query(
- db: &dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
- let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) {
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db
- .trait_signature(it.hir_trait_id())
- .name
- .display(db, Edition::LATEST)
- .to_string(),
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
- _ => "??".to_owned(),
- })
- .entered();
-
- if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(projection_ty),
- ..
- }))) = &goal.value.goal.data(Interner)
- && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
- {
- // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
- return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
- }
-
- // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
- // we should get rid of it when talking to chalk.
- let goal = goal
- .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
- .unwrap();
-
- // We currently don't deal with universes (I think / hope they're not yet
- // relevant for our use cases?)
- next_trait_solve(db, krate, block, goal)
-}
-
-fn solve_nextsolver<'db>(
- db: &'db dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
-) -> Result<
- (HasChanged, Certainty, rustc_type_ir::Canonical<DbInterner<'db>, Vec<GenericArg<'db>>>),
- rustc_type_ir::solve::NoSolution,
-> {
- // FIXME: should use analysis_in_body, but that needs GenericDefId::Block
- let context = SolverContext(
- DbInterner::new_with(db, Some(krate), block)
- .infer_ctxt()
- .build(TypingMode::non_body_analysis()),
- );
-
- match goal.canonical.value.goal.data(Interner) {
- // FIXME: args here should be...what? not empty
- GoalData::All(goals) if goals.is_empty(Interner) => {
- return Ok((HasChanged::No, Certainty::Yes, mini_canonicalize(context, vec![])));
- }
- _ => {}
- }
-
- let goal = goal.canonical.to_nextsolver(context.cx());
- tracing::info!(?goal);
-
- let (goal, var_values) = context.instantiate_canonical(&goal);
- tracing::info!(?var_values);
-
- let res = context.evaluate_root_goal(goal, Span::dummy(), None);
-
- let vars =
- var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect();
- let canonical_var_values = mini_canonicalize(context, vars);
-
- let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values));
-
- tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
-
- res
-}
-
#[derive(Clone, Debug, PartialEq)]
pub enum NextTraitSolveResult {
- Certain(chalk_ir::Canonical<chalk_ir::ConstrainedSubst<Interner>>),
- Uncertain(chalk_ir::Canonical<chalk_ir::Substitution<Interner>>),
+ Certain,
+ Uncertain,
NoSolution,
}
@@ -260,75 +95,17 @@
}
pub fn certain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Certain(..))
+ matches!(self, NextTraitSolveResult::Certain)
}
pub fn uncertain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Uncertain(..))
- }
-}
-
-pub fn next_trait_solve(
- db: &dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
- let detail = match &goal.value.goal.data(Interner) {
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
- db.trait_signature(it.hir_trait_id()).name.display(db, Edition::LATEST).to_string()
- }
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
- _ => "??".to_owned(),
- };
- let _p = tracing::info_span!("next_trait_solve", ?detail).entered();
- tracing::info!("next_trait_solve({:?})", goal.value.goal);
-
- if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(projection_ty),
- ..
- }))) = &goal.value.goal.data(Interner)
- && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
- {
- // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
- // FIXME
- return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
- }
-
- // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
- // we should get rid of it when talking to chalk.
- let goal = goal
- .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
- .unwrap();
-
- // We currently don't deal with universes (I think / hope they're not yet
- // relevant for our use cases?)
- let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
- tracing::info!(?u_canonical);
-
- let next_solver_res = solve_nextsolver(db, krate, block, &u_canonical);
-
- match next_solver_res {
- Err(_) => NextTraitSolveResult::NoSolution,
- Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
- convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args),
- ),
- Ok((_, Certainty::Maybe { .. }, args)) => {
- let subst = convert_canonical_args_for_result(
- DbInterner::new_with(db, Some(krate), block),
- args,
- );
- NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
- binders: subst.binders,
- value: subst.value.subst,
- })
- }
+ matches!(self, NextTraitSolveResult::Uncertain)
}
}
pub fn next_trait_solve_canonical_in_ctxt<'db>(
infer_ctxt: &InferCtxt<'db>,
- goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>,
+ goal: Canonical<'db, Goal<'db, Predicate<'db>>>,
) -> NextTraitSolveResult {
let context = SolverContext(infer_ctxt.clone());
@@ -339,33 +116,21 @@
let res = context.evaluate_root_goal(goal, Span::dummy(), None);
- let vars =
- var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect();
- let canonical_var_values = mini_canonicalize(context, vars);
-
- let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values));
+ let res = res.map(|r| (r.has_changed, r.certainty));
tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
match res {
Err(_) => NextTraitSolveResult::NoSolution,
- Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
- convert_canonical_args_for_result(infer_ctxt.interner, args),
- ),
- Ok((_, Certainty::Maybe { .. }, args)) => {
- let subst = convert_canonical_args_for_result(infer_ctxt.interner, args);
- NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
- binders: subst.binders,
- value: subst.value.subst,
- })
- }
+ Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
+ Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
}
}
/// Solve a trait goal using next trait solver.
pub fn next_trait_solve_in_ctxt<'db, 'a>(
infer_ctxt: &'a InferCtxt<'db>,
- goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,
+ goal: Goal<'db, Predicate<'db>>,
) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> {
tracing::info!(?goal);
@@ -459,7 +224,7 @@
/// This should not be used in `hir-ty`, only in `hir`.
pub fn implements_trait_unique<'db>(
- ty: crate::next_solver::Ty<'db>,
+ ty: Ty<'db>,
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
@@ -474,7 +239,7 @@
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
- args: crate::next_solver::GenericArgs<'db>,
+ args: GenericArgs<'db>,
) -> bool {
implements_trait_unique_impl(db, env, trait_, &mut |_| args)
}
@@ -483,7 +248,7 @@
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
- create_args: &mut dyn FnMut(&InferCtxt<'db>) -> crate::next_solver::GenericArgs<'db>,
+ create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>,
) -> bool {
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
// FIXME(next-solver): I believe this should be `PostAnalysis`.
@@ -491,7 +256,7 @@
let args = create_args(&infcx);
let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args);
- let goal = crate::next_solver::Goal::new(interner, env.env, trait_ref);
+ let goal = Goal::new(interner, env.env, trait_ref);
let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal);
matches!(result, Ok((_, Certainty::Yes)))
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index e989e4c..ca5e33f 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -1,41 +1,30 @@
//! Helper functions for working with def, which don't need to be a separate
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
-use std::{cell::LazyCell, iter};
+use std::cell::LazyCell;
use base_db::{
Crate,
target::{self, TargetData},
};
-use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder};
use hir_def::{
- EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
+ EnumId, EnumVariantId, FunctionId, Lookup, TraitId,
db::DefDatabase,
hir::generics::WherePredicate,
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
};
-use hir_expand::name::Name;
use intern::sym;
use rustc_abi::TargetDataLayout;
-use rustc_hash::FxHashSet;
-use rustc_type_ir::inherent::{IntoKind, SliceLike};
use smallvec::{SmallVec, smallvec};
use span::Edition;
use crate::{
- ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef,
- TraitRefExt, Ty,
- consteval::unknown_const,
+ TargetFeatures,
db::HirDatabase,
layout::{Layout, TagEncoding},
mir::pad16,
- next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, NextSolverToChalk, convert_args_for_result},
- },
- to_chalk_trait_id,
};
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator<Item = TraitId> + '_ {
@@ -76,49 +65,6 @@
result
}
-/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
-/// super traits. The original trait ref will be included. So the difference to
-/// `all_super_traits` is that we keep track of type parameters; for example if
-/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
-/// `Self: OtherTrait<i32>`.
-pub(super) fn all_super_trait_refs<T>(
- db: &dyn HirDatabase,
- trait_ref: TraitRef,
- cb: impl FnMut(TraitRef) -> Option<T>,
-) -> Option<T> {
- let seen = iter::once(trait_ref.trait_id).collect();
- SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb)
-}
-
-struct SuperTraits<'a> {
- db: &'a dyn HirDatabase,
- stack: Vec<TraitRef>,
- seen: FxHashSet<ChalkTraitId>,
-}
-
-impl SuperTraits<'_> {
- fn elaborate(&mut self, trait_ref: &TraitRef) {
- direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
- if !self.seen.contains(&trait_ref.trait_id) {
- self.stack.push(trait_ref);
- }
- });
- }
-}
-
-impl Iterator for SuperTraits<'_> {
- type Item = TraitRef;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(next) = self.stack.pop() {
- self.elaborate(&next);
- Some(next)
- } else {
- None
- }
- }
-}
-
fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = LazyCell::new(|| trait_.resolver(db));
let (generic_params, store) = db.generic_params_and_store(trait_.into());
@@ -149,62 +95,6 @@
.for_each(cb);
}
-fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
- let interner = DbInterner::new_with(db, None, None);
- let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
- let trait_self = match generic_params.trait_self_param() {
- Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
- None => return,
- };
- let trait_ref_args: crate::next_solver::GenericArgs<'_> =
- trait_ref.substitution.to_nextsolver(interner);
- db.generic_predicates_for_param_ns(trait_self.parent, trait_self, None)
- .iter()
- .filter_map(|pred| {
- let pred = pred.kind();
- // FIXME: how to correctly handle higher-ranked bounds here?
- let pred = pred.no_bound_vars().expect("FIXME unexpected higher-ranked trait bound");
- match pred {
- rustc_type_ir::ClauseKind::Trait(t) => {
- let t =
- rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args);
- let trait_id = to_chalk_trait_id(t.def_id().0);
-
- let substitution =
- convert_args_for_result(interner, t.trait_ref.args.as_slice());
- let tr = chalk_ir::TraitRef { trait_id, substitution };
- Some(tr)
- }
- _ => None,
- }
- })
- .for_each(cb);
-}
-
-pub(super) fn associated_type_by_name_including_super_traits(
- db: &dyn HirDatabase,
- trait_ref: TraitRef,
- name: &Name,
-) -> Option<(TraitRef, TypeAliasId)> {
- all_super_trait_refs(db, trait_ref, |t| {
- let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?;
- Some((t, assoc_type))
- })
-}
-
-pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution);
-
-impl<'a> ClosureSubst<'a> {
- pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty {
- let interner = DbInterner::new_with(db, None, None);
- let subst =
- <Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(
- self.0, interner,
- );
- subst.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.to_chalk(interner)
- }
-}
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Unsafety {
Safe,
@@ -277,41 +167,6 @@
}
}
-pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
- pub(crate) db: &'a dyn HirDatabase,
-}
-
-impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
- type Error = ();
-
- fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn try_fold_const(
- &mut self,
- constant: Const,
- _outer_binder: DebruijnIndex,
- ) -> Result<Const, Self::Error> {
- if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value
- && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned
- {
- let interner = DbInterner::conjure();
- if let Ok(eval) = self.db.const_eval(*id, subst.to_nextsolver(interner), None) {
- return Ok(eval.to_chalk(interner));
- } else {
- return Ok(unknown_const(constant.data(Interner).ty.to_nextsolver(interner))
- .to_chalk(interner));
- }
- }
- Ok(constant)
- }
-}
-
pub(crate) fn detect_variant_from_bytes<'a>(
layout: &'a Layout,
db: &dyn HirDatabase,
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index 0ff1101..b57bf03 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -13,43 +13,45 @@
//! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach
//! while installing firewall per item queries to prevent invalidation issues.
-use crate::db::HirDatabase;
-use crate::generics::{Generics, generics};
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
-use crate::{
- AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime,
- LifetimeData, Ty, TyKind,
+use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags};
+use rustc_ast_ir::Mutability;
+use rustc_type_ir::{
+ Variance,
+ inherent::{AdtDef, IntoKind, SliceLike},
};
-use chalk_ir::Mutability;
-use hir_def::signatures::StructFlags;
-use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId};
-use std::fmt;
-use std::ops::Not;
use stdx::never;
-use triomphe::Arc;
-pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Arc<[Variance]>> {
+use crate::{
+ db::HirDatabase,
+ generics::{Generics, generics},
+ next_solver::{
+ Const, ConstKind, DbInterner, ExistentialPredicate, GenericArg, GenericArgs, Region,
+ RegionKind, Term, Ty, TyKind, VariancesOf,
+ },
+};
+
+pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> {
tracing::debug!("variances_of(def={:?})", def);
+ let interner = DbInterner::new_with(db, None, None);
match def {
GenericDefId::FunctionId(_) => (),
GenericDefId::AdtId(adt) => {
if let AdtId::StructId(id) = adt {
let flags = &db.struct_signature(id).flags;
if flags.contains(StructFlags::IS_UNSAFE_CELL) {
- return Some(Arc::from_iter(vec![Variance::Invariant; 1]));
+ return VariancesOf::new_from_iter(interner, [Variance::Invariant]);
} else if flags.contains(StructFlags::IS_PHANTOM_DATA) {
- return Some(Arc::from_iter(vec![Variance::Covariant; 1]));
+ return VariancesOf::new_from_iter(interner, [Variance::Covariant]);
}
}
}
- _ => return None,
+ _ => return VariancesOf::new_from_iter(interner, []),
}
let generics = generics(db, def);
let count = generics.len();
if count == 0 {
- return None;
+ return VariancesOf::new_from_iter(interner, []);
}
let mut variances =
Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
@@ -69,7 +71,7 @@
}
}
- variances.is_empty().not().then(|| Arc::from_iter(variances))
+ VariancesOf::new_from_iter(interner, variances)
}
// pub(crate) fn variances_of_cycle_fn(
@@ -81,130 +83,36 @@
// salsa::CycleRecoveryAction::Iterate
// }
+fn glb(v1: Variance, v2: Variance) -> Variance {
+ // Greatest lower bound of the variance lattice as defined in The Paper:
+ //
+ // *
+ // - +
+ // o
+ match (v1, v2) {
+ (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
+
+ (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
+ (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
+
+ (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
+
+ (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
+
+ (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
+ }
+}
+
pub(crate) fn variances_of_cycle_initial(
db: &dyn HirDatabase,
def: GenericDefId,
-) -> Option<Arc<[Variance]>> {
+) -> VariancesOf<'_> {
+ let interner = DbInterner::new_with(db, None, None);
let generics = generics(db, def);
let count = generics.len();
- if count == 0 {
- return None;
- }
// FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query.
- Some(Arc::from(vec![Variance::Invariant; count]))
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum Variance {
- Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
- Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
- Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
- Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
-}
-
-impl fmt::Display for Variance {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Variance::Covariant => write!(f, "covariant"),
- Variance::Invariant => write!(f, "invariant"),
- Variance::Contravariant => write!(f, "contravariant"),
- Variance::Bivariant => write!(f, "bivariant"),
- }
- }
-}
-
-impl Variance {
- /// `a.xform(b)` combines the variance of a context with the
- /// variance of a type with the following meaning. If we are in a
- /// context with variance `a`, and we encounter a type argument in
- /// a position with variance `b`, then `a.xform(b)` is the new
- /// variance with which the argument appears.
- ///
- /// Example 1:
- /// ```ignore (illustrative)
- /// *mut Vec<i32>
- /// ```
- /// Here, the "ambient" variance starts as covariant. `*mut T` is
- /// invariant with respect to `T`, so the variance in which the
- /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
- /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
- /// respect to its type argument `T`, and hence the variance of
- /// the `i32` here is `Invariant.xform(Covariant)`, which results
- /// (again) in `Invariant`.
- ///
- /// Example 2:
- /// ```ignore (illustrative)
- /// fn(*const Vec<i32>, *mut Vec<i32)
- /// ```
- /// The ambient variance is covariant. A `fn` type is
- /// contravariant with respect to its parameters, so the variance
- /// within which both pointer types appear is
- /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
- /// T` is covariant with respect to `T`, so the variance within
- /// which the first `Vec<i32>` appears is
- /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
- /// is true for its `i32` argument. In the `*mut T` case, the
- /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
- /// and hence the outermost type is `Invariant` with respect to
- /// `Vec<i32>` (and its `i32` argument).
- ///
- /// Source: Figure 1 of "Taming the Wildcards:
- /// Combining Definition- and Use-Site Variance" published in PLDI'11.
- fn xform(self, v: Variance) -> Variance {
- match (self, v) {
- // Figure 1, column 1.
- (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
- (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
- (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
- (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
-
- // Figure 1, column 2.
- (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
- (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
- (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
- (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
-
- // Figure 1, column 3.
- (Variance::Invariant, _) => Variance::Invariant,
-
- // Figure 1, column 4.
- (Variance::Bivariant, _) => Variance::Bivariant,
- }
- }
-
- fn glb(self, v: Variance) -> Variance {
- // Greatest lower bound of the variance lattice as
- // defined in The Paper:
- //
- // *
- // - +
- // o
- match (self, v) {
- (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
-
- (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
- (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
-
- (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
-
- (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
-
- (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
- }
- }
-
- pub fn invariant(self) -> Self {
- self.xform(Variance::Invariant)
- }
-
- pub fn covariant(self) -> Self {
- self.xform(Variance::Covariant)
- }
-
- pub fn contravariant(self) -> Self {
- self.xform(Variance::Contravariant)
- }
+ VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count))
}
struct Context<'db> {
@@ -213,17 +121,16 @@
variances: Vec<Variance>,
}
-impl Context<'_> {
+impl<'db> Context<'db> {
fn solve(mut self) -> Vec<Variance> {
tracing::debug!("solve(generics={:?})", self.generics);
match self.generics.def() {
GenericDefId::AdtId(adt) => {
let db = self.db;
let mut add_constraints_from_variant = |variant| {
- let subst = self.generics.placeholder_subst(db);
for (_, field) in db.field_types(variant).iter() {
self.add_constraints_from_ty(
- &field.clone().substitute(Interner, &subst),
+ field.instantiate_identity(),
Variance::Covariant,
);
}
@@ -239,16 +146,9 @@
}
}
GenericDefId::FunctionId(f) => {
- let subst = self.generics.placeholder_subst(self.db);
- let interner = DbInterner::new_with(self.db, None, None);
- let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
- let sig = self
- .db
- .callable_item_signature(f.into())
- .instantiate(interner, args)
- .skip_binder()
- .to_chalk(interner);
- self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant);
+ let sig =
+ self.db.callable_item_signature(f.into()).instantiate_identity().skip_binder();
+ self.add_constraints_from_sig(sig.inputs_and_output.iter(), Variance::Covariant);
}
_ => {}
}
@@ -276,122 +176,102 @@
/// Adds constraints appropriate for an instance of `ty` appearing
/// in a context with the generics defined in `generics` and
/// ambient variance `variance`
- fn add_constraints_from_ty(&mut self, ty: &Ty, variance: Variance) {
+ fn add_constraints_from_ty(&mut self, ty: Ty<'db>, variance: Variance) {
tracing::debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance);
- match ty.kind(Interner) {
- TyKind::Scalar(_) | TyKind::Never | TyKind::Str | TyKind::Foreign(..) => {
+ match ty.kind() {
+ TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Char
+ | TyKind::Bool
+ | TyKind::Never
+ | TyKind::Str
+ | TyKind::Foreign(..) => {
// leaf type -- noop
}
- TyKind::FnDef(..) | TyKind::Coroutine(..) | TyKind::Closure(..) => {
+ TyKind::FnDef(..)
+ | TyKind::Coroutine(..)
+ | TyKind::CoroutineClosure(..)
+ | TyKind::Closure(..) => {
never!("Unexpected unnameable type in variance computation: {:?}", ty);
}
- TyKind::Ref(mutbl, lifetime, ty) => {
+ TyKind::Ref(lifetime, ty, mutbl) => {
self.add_constraints_from_region(lifetime, variance);
- self.add_constraints_from_mt(ty, *mutbl, variance);
+ self.add_constraints_from_mt(ty, mutbl, variance);
}
TyKind::Array(typ, len) => {
- self.add_constraints_from_const(len, variance);
+ self.add_constraints_from_const(len);
self.add_constraints_from_ty(typ, variance);
}
TyKind::Slice(typ) => {
self.add_constraints_from_ty(typ, variance);
}
- TyKind::Raw(mutbl, ty) => {
- self.add_constraints_from_mt(ty, *mutbl, variance);
+ TyKind::RawPtr(ty, mutbl) => {
+ self.add_constraints_from_mt(ty, mutbl, variance);
}
- TyKind::Tuple(_, subtys) => {
- for subty in subtys.type_parameters(Interner) {
- self.add_constraints_from_ty(&subty, variance);
+ TyKind::Tuple(subtys) => {
+ for subty in subtys {
+ self.add_constraints_from_ty(subty, variance);
}
}
TyKind::Adt(def, args) => {
- self.add_constraints_from_args(def.0.into(), args.as_slice(Interner), variance);
+ self.add_constraints_from_args(def.def_id().0.into(), args, variance);
}
- TyKind::Alias(AliasTy::Opaque(opaque)) => {
- self.add_constraints_from_invariant_args(
- opaque.substitution.as_slice(Interner),
- variance,
- );
+ TyKind::Alias(_, alias) => {
+ // FIXME: Probably not correct wrt. opaques.
+ self.add_constraints_from_invariant_args(alias.args);
}
- TyKind::Alias(AliasTy::Projection(proj)) => {
- self.add_constraints_from_invariant_args(
- proj.substitution.as_slice(Interner),
- variance,
- );
- }
- // FIXME: check this
- TyKind::AssociatedType(_, subst) => {
- self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
- }
- // FIXME: check this
- TyKind::OpaqueType(_, subst) => {
- self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
- }
- TyKind::Dyn(it) => {
+ TyKind::Dynamic(bounds, region) => {
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
- self.add_constraints_from_region(&it.lifetime, variance);
+ self.add_constraints_from_region(region, variance);
- if let Some(trait_ref) = it.principal() {
- // Trait are always invariant so we can take advantage of that.
- self.add_constraints_from_invariant_args(
- trait_ref
- .map(|it| it.map(|it| it.substitution.clone()))
- .substitute(
- Interner,
- &[GenericArg::new(
- Interner,
- chalk_ir::GenericArgData::Ty(TyKind::Error.intern(Interner)),
- )],
- )
- .skip_binders()
- .as_slice(Interner),
- variance,
- );
+ for bound in bounds {
+ match bound.skip_binder() {
+ ExistentialPredicate::Trait(trait_ref) => {
+ self.add_constraints_from_invariant_args(trait_ref.args)
+ }
+ ExistentialPredicate::Projection(projection) => {
+ self.add_constraints_from_invariant_args(projection.args);
+ match projection.term {
+ Term::Ty(ty) => {
+ self.add_constraints_from_ty(ty, Variance::Invariant)
+ }
+ Term::Const(konst) => self.add_constraints_from_const(konst),
+ }
+ }
+ ExistentialPredicate::AutoTrait(_) => {}
+ }
}
-
- // FIXME
- // for projection in data.projection_bounds() {
- // match projection.skip_binder().term.unpack() {
- // TyKind::TermKind::Ty(ty) => {
- // self.add_constraints_from_ty( ty, self.invariant);
- // }
- // TyKind::TermKind::Const(c) => {
- // self.add_constraints_from_const( c, self.invariant)
- // }
- // }
- // }
}
// Chalk has no params, so use placeholders for now?
- TyKind::Placeholder(index) => {
- let idx = crate::from_placeholder_idx(self.db, *index).0;
- let index = self.generics.type_or_const_param_idx(idx).unwrap();
- self.constrain(index, variance);
+ TyKind::Param(param) => self.constrain(param.index as usize, variance),
+ TyKind::FnPtr(sig, _) => {
+ self.add_constraints_from_sig(sig.skip_binder().inputs_and_output.iter(), variance);
}
- TyKind::Function(f) => {
- self.add_constraints_from_sig(
- f.substitution.0.iter(Interner).filter_map(move |p| p.ty(Interner)),
- variance,
- );
- }
- TyKind::Error => {
+ TyKind::Error(_) => {
// we encounter this when walking the trait references for object
// types, where we use Error as the Self type
}
- TyKind::CoroutineWitness(..) | TyKind::BoundVar(..) | TyKind::InferenceVar(..) => {
+ TyKind::Bound(..) => {}
+ TyKind::CoroutineWitness(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Infer(..)
+ | TyKind::UnsafeBinder(..)
+ | TyKind::Pat(..) => {
never!("unexpected type encountered in variance inference: {:?}", ty)
}
}
}
- fn add_constraints_from_invariant_args(&mut self, args: &[GenericArg], variance: Variance) {
- let variance_i = variance.invariant();
-
- for k in args {
- match k.data(Interner) {
- GenericArgData::Lifetime(lt) => self.add_constraints_from_region(lt, variance_i),
- GenericArgData::Ty(ty) => self.add_constraints_from_ty(ty, variance_i),
- GenericArgData::Const(val) => self.add_constraints_from_const(val, variance_i),
+ fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) {
+ for k in args.iter() {
+ match k {
+ GenericArg::Lifetime(lt) => {
+ self.add_constraints_from_region(lt, Variance::Invariant)
+ }
+ GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, Variance::Invariant),
+ GenericArg::Const(val) => self.add_constraints_from_const(val),
}
}
}
@@ -401,51 +281,40 @@
fn add_constraints_from_args(
&mut self,
def_id: GenericDefId,
- args: &[GenericArg],
+ args: GenericArgs<'db>,
variance: Variance,
) {
- // We don't record `inferred_starts` entries for empty generics.
if args.is_empty() {
return;
}
- let Some(variances) = self.db.variances_of(def_id) else {
- return;
- };
+ let variances = self.db.variances_of(def_id);
- for (i, k) in args.iter().enumerate() {
- match k.data(Interner) {
- GenericArgData::Lifetime(lt) => {
- self.add_constraints_from_region(lt, variance.xform(variances[i]))
- }
- GenericArgData::Ty(ty) => {
- self.add_constraints_from_ty(ty, variance.xform(variances[i]))
- }
- GenericArgData::Const(val) => self.add_constraints_from_const(val, variance),
+ for (k, v) in args.iter().zip(variances) {
+ match k {
+ GenericArg::Lifetime(lt) => self.add_constraints_from_region(lt, variance.xform(v)),
+ GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, variance.xform(v)),
+ GenericArg::Const(val) => self.add_constraints_from_const(val),
}
}
}
/// Adds constraints appropriate for a const expression `val`
/// in a context with ambient variance `variance`
- fn add_constraints_from_const(&mut self, c: &Const, variance: Variance) {
- match &c.data(Interner).value {
- chalk_ir::ConstValue::Concrete(c) => {
- if let ConstScalar::UnevaluatedConst(_, subst) = &c.interned {
- self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
- }
- }
+ fn add_constraints_from_const(&mut self, c: Const<'db>) {
+ match c.kind() {
+ ConstKind::Unevaluated(c) => self.add_constraints_from_invariant_args(c.args),
_ => {}
}
}
/// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance`
- fn add_constraints_from_sig<'a>(
+ fn add_constraints_from_sig(
&mut self,
- mut sig_tys: impl DoubleEndedIterator<Item = &'a Ty>,
+ mut sig_tys: impl DoubleEndedIterator<Item = Ty<'db>>,
variance: Variance,
) {
- let contra = variance.contravariant();
+ let contra = variance.xform(Variance::Contravariant);
let Some(output) = sig_tys.next_back() else {
return never!("function signature has no return type");
};
@@ -457,27 +326,26 @@
/// Adds constraints appropriate for a region appearing in a
/// context with ambient variance `variance`
- fn add_constraints_from_region(&mut self, region: &Lifetime, variance: Variance) {
+ fn add_constraints_from_region(&mut self, region: Region<'db>, variance: Variance) {
tracing::debug!(
"add_constraints_from_region(region={:?}, variance={:?})",
region,
variance
);
- match region.data(Interner) {
- LifetimeData::Placeholder(index) => {
- let idx = crate::lt_from_placeholder_idx(self.db, *index).0;
- let inferred = self.generics.lifetime_idx(idx).unwrap();
- self.constrain(inferred, variance);
- }
- LifetimeData::Static => {}
- LifetimeData::BoundVar(..) => {
+ match region.kind() {
+ RegionKind::ReEarlyParam(param) => self.constrain(param.index as usize, variance),
+ RegionKind::ReStatic => {}
+ RegionKind::ReBound(..) => {
// Either a higher-ranked region inside of a type or a
// late-bound function parameter.
//
// We do not compute constraints for either of these.
}
- LifetimeData::Error => {}
- LifetimeData::Phantom(..) | LifetimeData::InferenceVar(..) | LifetimeData::Erased => {
+ RegionKind::ReError(_) => {}
+ RegionKind::ReLateParam(..)
+ | RegionKind::RePlaceholder(..)
+ | RegionKind::ReVar(..)
+ | RegionKind::ReErased => {
// We don't expect to see anything but 'static or bound
// regions when visiting member types or method types.
never!(
@@ -491,11 +359,11 @@
/// Adds constraints appropriate for a mutability-type pair
/// appearing in a context with ambient variance `variance`
- fn add_constraints_from_mt(&mut self, ty: &Ty, mt: Mutability, variance: Variance) {
+ fn add_constraints_from_mt(&mut self, ty: Ty<'db>, mt: Mutability, variance: Variance) {
self.add_constraints_from_ty(
ty,
match mt {
- Mutability::Mut => variance.invariant(),
+ Mutability::Mut => Variance::Invariant,
Mutability::Not => variance,
},
);
@@ -508,7 +376,7 @@
self.variances[index],
variance
);
- self.variances[index] = self.variances[index].glb(variance);
+ self.variances[index] = glb(self.variances[index], variance);
}
}
@@ -519,6 +387,7 @@
AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource,
};
use itertools::Itertools;
+ use rustc_type_ir::{Variance, inherent::SliceLike};
use stdx::format_to;
use syntax::{AstNode, ast::HasName};
use test_fixture::WithFixture;
@@ -1037,26 +906,21 @@
let loc = it.lookup(&db);
loc.source(&db).value.name().unwrap()
}
- GenericDefId::TraitId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.name().unwrap()
- }
- GenericDefId::TypeAliasId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.name().unwrap()
- }
- GenericDefId::ImplId(_) => return None,
- GenericDefId::ConstId(_) => return None,
- GenericDefId::StaticId(_) => return None,
+ GenericDefId::TraitId(_)
+ | GenericDefId::TypeAliasId(_)
+ | GenericDefId::ImplId(_)
+ | GenericDefId::ConstId(_)
+ | GenericDefId::StaticId(_) => return None,
},
))
})
.sorted_by_key(|(_, n)| n.syntax().text_range().start());
let mut res = String::new();
for (def, name) in defs {
- let Some(variances) = db.variances_of(def) else {
+ let variances = db.variances_of(def);
+ if variances.is_empty() {
continue;
- };
+ }
format_to!(
res,
"{name}[{}]\n",
@@ -1072,10 +936,16 @@
&lifetime_param_data.name
}
})
- .zip_eq(&*variances)
+ .zip_eq(variances)
.format_with(", ", |(name, var), f| f(&format_args!(
- "{}: {var}",
- name.as_str()
+ "{}: {}",
+ name.as_str(),
+ match var {
+ Variance::Covariant => "covariant",
+ Variance::Invariant => "invariant",
+ Variance::Contravariant => "contravariant",
+ Variance::Bivariant => "bivariant",
+ },
)))
);
}
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 49bf843..d61c2ec 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -11,14 +11,15 @@
type_ref::{TypeBound, TypeRef, TypeRefId},
};
use hir_ty::{
- AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyBuilder, TyKind, WhereClause,
db::HirDatabase,
display::{
HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault,
hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
},
+ next_solver::ClauseKind,
};
use itertools::Itertools;
+use rustc_type_ir::inherent::IntoKind;
use crate::{
Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
@@ -27,8 +28,8 @@
TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
};
-impl HirDisplay for Function {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Function {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let db = f.db;
let data = db.function_signature(self.id);
let container = self.as_assoc_item(db).map(|it| it.container(db));
@@ -184,7 +185,10 @@
}
}
-fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+fn write_impl_header<'db>(
+ impl_: &Impl,
+ f: &mut HirFormatter<'_, 'db>,
+) -> Result<(), HirDisplayError> {
let db = f.db;
f.write_str("impl")?;
@@ -202,8 +206,8 @@
Ok(())
}
-impl HirDisplay for SelfParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for SelfParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let data = f.db.function_signature(self.func);
let param = *data.params.first().unwrap();
match &data.store[param] {
@@ -228,8 +232,8 @@
}
}
-impl HirDisplay for Adt {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Adt {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self {
Adt::Struct(it) => it.hir_fmt(f),
Adt::Union(it) => it.hir_fmt(f),
@@ -238,8 +242,8 @@
}
}
-impl HirDisplay for Struct {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Struct {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let module_id = self.module(f.db).id;
// FIXME: Render repr if its set explicitly?
write_visibility(module_id, self.visibility(f.db), f)?;
@@ -279,8 +283,8 @@
}
}
-impl HirDisplay for Enum {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Enum {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("enum ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -296,8 +300,8 @@
}
}
-impl HirDisplay for Union {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Union {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("union ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -312,12 +316,12 @@
}
}
-fn write_fields(
+fn write_fields<'db>(
fields: &[Field],
has_where_clause: bool,
limit: usize,
in_line: bool,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
let count = fields.len().min(limit);
let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') };
@@ -346,11 +350,11 @@
Ok(())
}
-fn write_variants(
+fn write_variants<'db>(
variants: &[Variant],
has_where_clause: bool,
limit: usize,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
let count = variants.len().min(limit);
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
@@ -386,23 +390,23 @@
Ok(())
}
-impl HirDisplay for Field {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Field {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
}
}
-impl HirDisplay for TupleField {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TupleField {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
}
}
-impl HirDisplay for Variant {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Variant {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
let data = self.id.fields(f.db);
match data.shape {
@@ -431,20 +435,20 @@
}
}
-impl HirDisplay for Type<'_> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Type<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
self.ty.hir_fmt(f)
}
}
-impl HirDisplay for TypeNs<'_> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeNs<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
self.ty.hir_fmt(f)
}
}
-impl HirDisplay for ExternCrateDecl {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for ExternCrateDecl {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("extern crate ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -455,8 +459,8 @@
}
}
-impl HirDisplay for GenericParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for GenericParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self {
GenericParam::TypeParam(it) => it.hir_fmt(f),
GenericParam::ConstParam(it) => it.hir_fmt(f),
@@ -465,8 +469,8 @@
}
}
-impl HirDisplay for TypeOrConstParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeOrConstParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.split(f.db) {
either::Either::Left(it) => it.hir_fmt(f),
either::Either::Right(it) => it.hir_fmt(f),
@@ -474,27 +478,22 @@
}
}
-impl HirDisplay for TypeParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let params = f.db.generic_params(self.id.parent());
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 = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(f.db, self.id.into()))
- .intern(Interner);
+ let ty = self.ty(f.db).ty;
let predicates = f.db.generic_predicates(self.id.parent());
let predicates = predicates
- .iter()
- .cloned()
- .map(|pred| pred.substitute(Interner, &substs))
- .filter(|wc| match wc.skip_binders() {
- WhereClause::Implemented(tr) => tr.self_type_parameter(Interner) == ty,
- WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _ }) => {
- proj.self_type_parameter(f.db) == ty
- }
- WhereClause::AliasEq(_) => false,
- WhereClause::TypeOutlives(to) => to.ty == ty,
- WhereClause::LifetimeOutlives(_) => false,
+ .instantiate_identity()
+ .into_iter()
+ .flatten()
+ .filter(|wc| match wc.kind().skip_binder() {
+ ClauseKind::Trait(tr) => tr.self_ty() == ty,
+ ClauseKind::Projection(proj) => proj.self_ty() == ty,
+ ClauseKind::TypeOutlives(to) => to.0 == ty,
+ _ => false,
})
.collect::<Vec<_>>();
@@ -507,7 +506,7 @@
return write_bounds_like_dyn_trait_with_prefix(
f,
"impl",
- Either::Left(&ty),
+ Either::Left(ty),
&predicates,
SizedByDefault::Sized { anchor: krate },
);
@@ -523,23 +522,18 @@
}
let sized_trait = LangItem::Sized.resolve_trait(f.db, krate);
- let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
- WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
- _ => false,
- });
+ let has_only_sized_bound =
+ predicates.iter().all(move |pred| match pred.kind().skip_binder() {
+ ClauseKind::Trait(it) => Some(it.def_id().0) == sized_trait,
+ _ => false,
+ });
let has_only_not_sized_bound = predicates.is_empty();
if !has_only_sized_bound || has_only_not_sized_bound {
let default_sized = SizedByDefault::Sized { anchor: krate };
write_bounds_like_dyn_trait_with_prefix(
f,
":",
- Either::Left(
- &hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(
- f.db,
- self.id.into(),
- ))
- .intern(Interner),
- ),
+ Either::Left(ty),
&predicates,
default_sized,
)?;
@@ -548,22 +542,22 @@
}
}
-impl HirDisplay for LifetimeParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for LifetimeParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))
}
}
-impl HirDisplay for ConstParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for ConstParam {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
}
}
-fn write_generic_params(
+fn write_generic_params<'db>(
def: GenericDefId,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
let (params, store) = f.db.generic_params_and_store(def);
if params.iter_lt().next().is_none()
@@ -578,7 +572,7 @@
f.write_char('<')?;
let mut first = true;
- let mut delim = |f: &mut HirFormatter<'_>| {
+ let mut delim = |f: &mut HirFormatter<'_, 'db>| {
if first {
first = false;
Ok(())
@@ -622,9 +616,9 @@
Ok(())
}
-fn write_where_clause(
+fn write_where_clause<'db>(
def: GenericDefId,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<bool, HirDisplayError> {
let (params, store) = f.db.generic_params_and_store(def);
if !has_disaplayable_predicates(f.db, ¶ms, &store) {
@@ -653,10 +647,10 @@
})
}
-fn write_where_predicates(
+fn write_where_predicates<'db>(
params: &GenericParams,
store: &ExpressionStore,
- f: &mut HirFormatter<'_>,
+ f: &mut HirFormatter<'_, 'db>,
) -> Result<(), HirDisplayError> {
use WherePredicate::*;
@@ -717,8 +711,8 @@
Ok(())
}
-impl HirDisplay for Const {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Const {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
let db = f.db;
let container = self.as_assoc_item(db).map(|it| it.container(db));
let mut module = self.module(db);
@@ -738,8 +732,8 @@
}
}
-impl HirDisplay for Static {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Static {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.static_signature(self.id);
f.write_str("static ")?;
@@ -752,14 +746,14 @@
}
}
-impl HirDisplay for TraitRef<'_> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TraitRef<'db> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
self.trait_ref.hir_fmt(f)
}
}
-impl HirDisplay for Trait {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Trait {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
// FIXME(trait-alias) needs special handling to print the equal sign
write_trait_header(self, f)?;
let def_id = GenericDefId::TraitId(self.id);
@@ -798,7 +792,10 @@
}
}
-fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+fn write_trait_header<'db>(
+ trait_: &Trait,
+ f: &mut HirFormatter<'_, 'db>,
+) -> Result<(), HirDisplayError> {
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
let data = f.db.trait_signature(trait_.id);
if data.flags.contains(TraitFlags::UNSAFE) {
@@ -812,8 +809,8 @@
Ok(())
}
-impl HirDisplay for TypeAlias {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeAlias {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.type_alias_signature(self.id);
write!(f, "type {}", data.name.display(f.db, f.edition()))?;
@@ -835,8 +832,8 @@
}
}
-impl HirDisplay for Module {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Module {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.parent(f.db) {
Some(m) => write_visibility(m.id, self.visibility(f.db), f)?,
None => {
@@ -853,8 +850,8 @@
}
}
-impl HirDisplay for Crate {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Crate {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.display_name(f.db) {
Some(name) => write!(f, "extern crate {name}"),
None => f.write_str("extern crate {unknown}"),
@@ -862,8 +859,8 @@
}
}
-impl HirDisplay for Macro {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Macro {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
match self.id {
hir_def::MacroId::Macro2Id(_) => f.write_str("macro"),
hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 55da277..2bb2f80 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -36,6 +36,7 @@
mod display;
use std::{
+ fmt,
mem::discriminant,
ops::{ControlFlow, Not},
};
@@ -74,7 +75,7 @@
TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef,
check_orphan_rules,
consteval::try_const_usize,
- db::InternedClosureId,
+ db::{InternedClosureId, InternedCoroutineId},
diagnostics::BodyValidationDiagnostic,
direct_super_traits, known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
@@ -91,7 +92,7 @@
use rustc_hash::FxHashSet;
use rustc_type_ir::{
AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor,
- inherent::{AdtDef, IntoKind, SliceLike, Term as _, Ty as _},
+ inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _},
};
use smallvec::SmallVec;
use span::{AstIdNode, Edition, FileId};
@@ -160,7 +161,7 @@
// FIXME: Properly encapsulate mir
hir_ty::mir,
hir_ty::{
- CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change,
+ CastError, FnAbi, PointerCast, attach_db, attach_db_allow_change,
consteval::ConstEvalError,
diagnostics::UnsafetyReason,
display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite},
@@ -170,6 +171,7 @@
method_resolution::TyFingerprint,
mir::{MirEvalError, MirLowerError},
next_solver::abi::Safety,
+ next_solver::clear_tls_solver_cache,
},
intern::{Symbol, sym},
};
@@ -1270,7 +1272,7 @@
let interner = DbInterner::new_with(db, Some(krate.base()), None);
let var_id = self.inner.parent.into();
- let field = db.field_types_ns(var_id)[self.inner.id];
+ let field = db.field_types(var_id)[self.inner.id];
let ty = field.instantiate(interner, self.args);
TypeNs::new(db, var_id, ty)
}
@@ -1349,7 +1351,7 @@
/// context of the field definition.
pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> {
let var_id = self.parent.into();
- let ty = db.field_types_ns(var_id)[self.id].skip_binder();
+ let ty = db.field_types(var_id)[self.id].skip_binder();
TypeNs::new(db, var_id, ty)
}
@@ -1367,7 +1369,7 @@
};
let interner = DbInterner::new_with(db, None, None);
let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty));
- let ty = db.field_types_ns(var_id)[self.id].instantiate(interner, args);
+ let ty = db.field_types(var_id)[self.id].instantiate(interner, args);
Type::new(db, var_id, ty)
}
@@ -1802,7 +1804,7 @@
let env = db.trait_environment(self.into());
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
let adt_id = AdtId::from(self);
- let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, _, id, _| {
+ let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| {
GenericArg::error_from_id(interner, id)
});
db.layout_of_adt(adt_id, args, env)
@@ -4110,7 +4112,39 @@
GenericParam::ConstParam(_) => return None,
GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?,
};
- db.variances_of(parent)?.get(index).copied()
+ db.variances_of(parent).get(index).map(Into::into)
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Variance {
+ Bivariant,
+ Covariant,
+ Contravariant,
+ Invariant,
+}
+
+impl From<rustc_type_ir::Variance> for Variance {
+ #[inline]
+ fn from(value: rustc_type_ir::Variance) -> Self {
+ match value {
+ rustc_type_ir::Variance::Covariant => Variance::Covariant,
+ rustc_type_ir::Variance::Invariant => Variance::Invariant,
+ rustc_type_ir::Variance::Contravariant => Variance::Contravariant,
+ rustc_type_ir::Variance::Bivariant => Variance::Bivariant,
+ }
+ }
+}
+
+impl fmt::Display for Variance {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let description = match self {
+ Variance::Bivariant => "bivariant",
+ Variance::Covariant => "covariant",
+ Variance::Contravariant => "contravariant",
+ Variance::Invariant => "invariant",
+ };
+ f.pad(description)
}
}
@@ -4151,8 +4185,7 @@
let resolver = self.id.parent().resolver(db);
let interner = DbInterner::new_with(db, None, None);
let index = hir_ty::param_idx(db, self.id.into()).unwrap();
- let name = self.name(db).symbol().clone();
- let ty = Ty::new_param(interner, self.id, index as u32, name);
+ let ty = Ty::new_param(interner, self.id, index as u32);
Type::new_with_resolver_inner(db, &resolver, ty)
}
@@ -4160,7 +4193,7 @@
/// parameter, not additional bounds that might be added e.g. by a method if
/// the parameter comes from an impl!
pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
- db.generic_predicates_for_param_ns(self.id.parent(), self.id.into(), None)
+ db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
.iter()
.filter_map(|pred| match &pred.kind().skip_binder() {
ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)),
@@ -4250,7 +4283,7 @@
fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg<'_>> {
let local_idx = hir_ty::param_idx(db, id)?;
- let defaults = db.generic_defaults_ns(id.parent);
+ let defaults = db.generic_defaults(id.parent);
let ty = defaults.get(local_idx)?;
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
Some(ty.instantiate_identity())
@@ -4525,16 +4558,27 @@
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+enum AnyClosureId {
+ ClosureId(InternedClosureId),
+ CoroutineClosureId(InternedCoroutineId),
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Closure<'db> {
- id: InternedClosureId,
+ id: AnyClosureId,
subst: GenericArgs<'db>,
}
impl<'db> Closure<'db> {
fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> {
let interner = DbInterner::new_with(db, None, None);
- Ty::new_closure(interner, self.id.into(), self.subst)
+ match self.id {
+ AnyClosureId::ClosureId(id) => Ty::new_closure(interner, id.into(), self.subst),
+ AnyClosureId::CoroutineClosureId(id) => {
+ Ty::new_coroutine_closure(interner, id.into(), self.subst)
+ }
+ }
}
pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
@@ -4552,20 +4596,28 @@
}
pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec<ClosureCapture<'db>> {
- let owner = db.lookup_intern_closure(self.id).0;
+ let AnyClosureId::ClosureId(id) = self.id else {
+ // FIXME: Infer coroutine closures' captures.
+ return Vec::new();
+ };
+ let owner = db.lookup_intern_closure(id).0;
let infer = db.infer(owner);
- let info = infer.closure_info(self.id);
+ let info = infer.closure_info(id);
info.0
.iter()
.cloned()
- .map(|capture| ClosureCapture { owner, closure: self.id, capture })
+ .map(|capture| ClosureCapture { owner, closure: id, capture })
.collect()
}
pub fn capture_types(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> {
- let owner = db.lookup_intern_closure(self.id).0;
+ let AnyClosureId::ClosureId(id) = self.id else {
+ // FIXME: Infer coroutine closures' captures.
+ return Vec::new();
+ };
+ let owner = db.lookup_intern_closure(id).0;
let infer = db.infer(owner);
- let (captures, _) = infer.closure_info(self.id);
+ let (captures, _) = infer.closure_info(id);
let env = db.trait_environment_for_body(owner);
captures
.iter()
@@ -4574,10 +4626,22 @@
}
pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait {
- let owner = db.lookup_intern_closure(self.id).0;
- let infer = db.infer(owner);
- let info = infer.closure_info(self.id);
- info.1
+ match self.id {
+ AnyClosureId::ClosureId(id) => {
+ let owner = db.lookup_intern_closure(id).0;
+ let infer = db.infer(owner);
+ let info = infer.closure_info(id);
+ info.1
+ }
+ AnyClosureId::CoroutineClosureId(_id) => {
+ // FIXME: Infer kind for coroutine closures.
+ match self.subst.as_coroutine_closure().kind() {
+ rustc_type_ir::ClosureKind::Fn => FnTrait::AsyncFn,
+ rustc_type_ir::ClosureKind::FnMut => FnTrait::AsyncFnMut,
+ rustc_type_ir::ClosureKind::FnOnce => FnTrait::AsyncFnOnce,
+ }
+ }
+ }
}
}
@@ -4851,7 +4915,7 @@
if variant_data.fields().is_empty() {
vec![]
} else {
- let field_types = self.interner.db().field_types_ns(id);
+ let field_types = self.interner.db().field_types(id);
variant_data
.fields()
.iter()
@@ -5091,28 +5155,14 @@
let interner = DbInterner::new_with(db, None, None);
let callee = match self.ty.kind() {
TyKind::Closure(id, subst) => Callee::Closure(id.0, subst),
+ TyKind::CoroutineClosure(id, subst) => Callee::CoroutineClosure(id.0, subst),
TyKind::FnPtr(..) => Callee::FnPtr,
TyKind::FnDef(id, _) => Callee::Def(id.0),
- kind => {
- // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
- let (ty, kind) = if let TyKind::Ref(_, ty, _) = kind {
- (ty, ty.kind())
- } else {
- (self.ty, kind)
- };
- if let TyKind::Closure(closure, subst) = kind {
- let sig = subst
- .split_closure_args_untupled()
- .closure_sig_as_fn_ptr_ty
- .callable_sig(interner)?;
- return Some(Callable {
- ty: self.clone(),
- sig,
- callee: Callee::Closure(closure.0, subst),
- is_bound_method: false,
- });
- }
- let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?;
+ // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
+ TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db),
+ _ => {
+ let (fn_trait, sig) =
+ hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?;
return Some(Callable {
ty: self.clone(),
sig,
@@ -5132,7 +5182,12 @@
pub fn as_closure(&self) -> Option<Closure<'db>> {
match self.ty.kind() {
- TyKind::Closure(id, subst) => Some(Closure { id: id.0, subst }),
+ TyKind::Closure(id, subst) => {
+ Some(Closure { id: AnyClosureId::ClosureId(id.0), subst })
+ }
+ TyKind::CoroutineClosure(id, subst) => {
+ Some(Closure { id: AnyClosureId::CoroutineClosureId(id.0), subst })
+ }
_ => None,
}
}
@@ -5184,7 +5239,7 @@
_ => return Vec::new(),
};
- db.field_types_ns(variant_id)
+ db.field_types(variant_id)
.iter()
.map(|(local_id, ty)| {
let def = Field { parent: variant_id.into(), id: local_id };
@@ -5791,6 +5846,7 @@
enum Callee<'db> {
Def(CallableDefId),
Closure(InternedClosureId, GenericArgs<'db>),
+ CoroutineClosure(InternedCoroutineId, GenericArgs<'db>),
FnPtr,
FnImpl(FnTrait),
}
@@ -5812,7 +5868,12 @@
Callee::Def(CallableDefId::EnumVariantId(it)) => {
CallableKind::TupleEnumVariant(it.into())
}
- Callee::Closure(id, ref subst) => CallableKind::Closure(Closure { id, subst: *subst }),
+ Callee::Closure(id, subst) => {
+ CallableKind::Closure(Closure { id: AnyClosureId::ClosureId(id), subst })
+ }
+ Callee::CoroutineClosure(id, subst) => {
+ CallableKind::Closure(Closure { id: AnyClosureId::CoroutineClosureId(id), subst })
+ }
Callee::FnPtr => CallableKind::FnPtr,
Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
}
@@ -6405,7 +6466,7 @@
args: impl IntoIterator<Item = Ty<'db>>,
) -> GenericArgs<'db> {
let mut args = args.into_iter();
- GenericArgs::for_item(interner, def_id, |_, _, id, _| {
+ GenericArgs::for_item(interner, def_id, |_, id, _| {
if matches!(id, GenericParamId::TypeParamId(_))
&& let Some(arg) = args.next()
{
@@ -6418,7 +6479,7 @@
fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool {
let params = db.generic_params(generic_def);
- let defaults = db.generic_defaults_ns(generic_def);
+ let defaults = db.generic_defaults(generic_def);
params
.iter_type_or_consts()
.filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_)))
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index eecca02..62ce3da 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1657,14 +1657,11 @@
) -> Option<Function> {
let interner = DbInterner::new_with(self.db, None, None);
let mut subst = subst.into_iter();
- let substs = hir_ty::next_solver::GenericArgs::for_item(
- interner,
- trait_.id.into(),
- |_, _, id, _| {
+ let substs =
+ hir_ty::next_solver::GenericArgs::for_item(interner, trait_.id.into(), |_, id, _| {
assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type");
subst.next().expect("too few subst").ty.into()
- },
- );
+ });
assert!(subst.next().is_none(), "too many subst");
Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into())
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8d2ba7e..15eab14 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -712,8 +712,7 @@
let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
- let field_ty =
- (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst);
+ let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst);
Some((
field.into(),
local,
@@ -735,8 +734,7 @@
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?;
- let field_ty =
- (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst);
+ let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst);
Some((
field.into(),
Type::new_with_resolver(db, &self.resolver, field_ty),
@@ -802,7 +800,7 @@
|variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {
let fields = variant.fields(db);
let field = fields.field(&field_name.as_name())?;
- let field_types = db.field_types_ns(variant);
+ let field_types = db.field_types(variant);
*container = Either::Right(field_types[field].instantiate(interner, subst));
let generic_def = match variant {
VariantId::EnumVariantId(it) => it.loc(db).parent.into(),
@@ -1255,7 +1253,7 @@
missing_fields: Vec<LocalFieldId>,
) -> Vec<(Field, Type<'db>)> {
let interner = DbInterner::new_with(db, None, None);
- let field_types = db.field_types_ns(variant);
+ let field_types = db.field_types(variant);
missing_fields
.into_iter()
diff --git a/crates/ide-assists/src/handlers/add_braces.rs b/crates/ide-assists/src/handlers/add_braces.rs
index 5af622e..99ee50f 100644
--- a/crates/ide-assists/src/handlers/add_braces.rs
+++ b/crates/ide-assists/src/handlers/add_braces.rs
@@ -1,14 +1,15 @@
use either::Either;
use syntax::{
- AstNode,
- ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
+ AstNode, T,
+ ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory},
+ match_ast,
};
use crate::{AssistContext, AssistId, Assists};
// Assist: add_braces
//
-// Adds braces to closure bodies and match arm expressions.
+// Adds braces to closure bodies, match arm expressions and assignment bodies.
//
// ```
// fn foo(n: i32) -> i32 {
@@ -29,6 +30,20 @@
// }
// }
// ```
+// ---
+// ```
+// fn foo(n: i32) -> i32 {
+// let x =$0 n + 2;
+// }
+// ```
+// ->
+// ```
+// fn foo(n: i32) -> i32 {
+// let x = {
+// n + 2
+// };
+// }
+// ```
pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let (expr_type, expr) = get_replacement_node(ctx)?;
@@ -37,16 +52,17 @@
match expr_type {
ParentType::ClosureExpr => "Add braces to this closure body",
ParentType::MatchArmExpr => "Add braces to this match arm expression",
+ ParentType::Assignment => "Add braces to this assignment expression",
},
expr.syntax().text_range(),
|builder| {
let make = SyntaxFactory::with_mappings();
let mut editor = builder.make_editor(expr.syntax());
- let block_expr = make.block_expr(None, Some(expr.clone()));
- block_expr.indent(expr.indent_level());
+ let new_expr = expr.reset_indent().indent(1.into());
+ let block_expr = make.block_expr(None, Some(new_expr));
- editor.replace(expr.syntax(), block_expr.syntax());
+ editor.replace(expr.syntax(), block_expr.indent(expr.indent_level()).syntax());
editor.add_mappings(make.finish_with_mappings());
builder.add_file_edits(ctx.vfs_file_id(), editor);
@@ -57,29 +73,38 @@
enum ParentType {
MatchArmExpr,
ClosureExpr,
+ Assignment,
}
fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> {
- let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>()?;
- if let Either::Left(match_arm) = &node {
+ let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>();
+ let (parent_type, body) = if let Some(eq_token) = ctx.find_token_syntax_at_offset(T![=]) {
+ let parent = eq_token.parent()?;
+ let body = match_ast! {
+ match parent {
+ ast::LetStmt(it) => it.initializer()?,
+ ast::LetExpr(it) => it.expr()?,
+ ast::Static(it) => it.body()?,
+ ast::Const(it) => it.body()?,
+ _ => return None,
+ }
+ };
+ (ParentType::Assignment, body)
+ } else if let Some(Either::Left(match_arm)) = &node {
let match_arm_expr = match_arm.expr()?;
-
- if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) {
- return None;
- }
-
- return Some((ParentType::MatchArmExpr, match_arm_expr));
- } else if let Either::Right(closure_expr) = &node {
+ (ParentType::MatchArmExpr, match_arm_expr)
+ } else if let Some(Either::Right(closure_expr)) = &node {
let body = closure_expr.body()?;
+ (ParentType::ClosureExpr, body)
+ } else {
+ return None;
+ };
- if matches!(body, ast::Expr::BlockExpr(_)) {
- return None;
- }
-
- return Some((ParentType::ClosureExpr, body));
+ if matches!(body, ast::Expr::BlockExpr(_)) {
+ return None;
}
- None
+ Some((parent_type, body))
}
#[cfg(test)]
@@ -135,6 +160,25 @@
}
#[test]
+ fn suggest_add_braces_for_assignment() {
+ check_assist(
+ add_braces,
+ r#"
+fn foo() {
+ let x =$0 n + 100;
+}
+"#,
+ r#"
+fn foo() {
+ let x = {
+ n + 100
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
fn no_assist_for_closures_with_braces() {
check_assist_not_applicable(
add_braces,
@@ -172,6 +216,41 @@
}
#[test]
+ fn multiple_indent() {
+ check_assist(
+ add_braces,
+ r#"
+fn foo() {
+ {
+ match n {
+ Some(n) $0=> foo(
+ 29,
+ 30,
+ ),
+ _ => ()
+ };
+ }
+}
+"#,
+ r#"
+fn foo() {
+ {
+ match n {
+ Some(n) => {
+ foo(
+ 29,
+ 30,
+ )
+ },
+ _ => ()
+ };
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn no_assist_for_match_with_braces() {
check_assist_not_applicable(
add_braces,
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 8802a54..7843ab9 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -8,8 +8,7 @@
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
use itertools::Itertools;
use syntax::ToSmolStr;
-use syntax::ast::edit::IndentLevel;
-use syntax::ast::edit_in_place::Indent;
+use syntax::ast::edit::{AstNodeEdit, IndentLevel};
use syntax::ast::syntax_factory::SyntaxFactory;
use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make};
@@ -261,6 +260,7 @@
true
}
})
+ .map(|arm| arm.reset_indent().indent(IndentLevel(1)))
.collect();
let first_new_arm_idx = arms.len();
@@ -300,7 +300,7 @@
};
let mut editor = builder.make_editor(&old_place);
- new_match_arm_list.indent(IndentLevel::from_node(&old_place));
+ let new_match_arm_list = new_match_arm_list.indent(IndentLevel::from_node(&old_place));
editor.replace(old_place, new_match_arm_list.syntax());
if let Some(cap) = ctx.config.snippet_cap {
@@ -918,6 +918,39 @@
}
#[test]
+ fn partial_fill_option_with_indentation() {
+ check_assist(
+ add_missing_match_arms,
+ r#"
+//- minicore: option
+fn main() {
+ match None$0 {
+ None => {
+ foo(
+ "foo",
+ "bar",
+ );
+ }
+ }
+}
+"#,
+ r#"
+fn main() {
+ match None {
+ None => {
+ foo(
+ "foo",
+ "bar",
+ );
+ }
+ Some(${1:_}) => ${2:todo!()},$0
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn partial_fill_or_pat() {
check_assist(
add_missing_match_arms,
diff --git a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index 2cda6d6..ca14233 100644
--- a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -805,7 +805,6 @@
);
}
- #[ignore = "FIXME(next-solver): Fix async closures"]
#[test]
fn replaces_async_closure_with_async_fn() {
check_assist(
diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 8d27574..e518c39 100644
--- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -187,6 +187,7 @@
return None;
}
+ // FIXME: Processing RecordPat and RecordExpr for unordered fields, and insert RestPat
let parent = full_path.syntax().parent()?;
match_ast! {
match parent {
@@ -202,6 +203,9 @@
.record_pat_field_list()?
.fields()
.filter_map(|pat| pat.pat())
+ .chain(record_struct_pat.record_pat_field_list()?
+ .rest_pat()
+ .map(Into::into))
)
.to_string()
);
@@ -347,6 +351,37 @@
}
#[test]
+ fn convert_struct_and_rest_pat() {
+ check_assist(
+ convert_named_struct_to_tuple_struct,
+ r#"
+struct Inner;
+struct A$0 { inner: Inner }
+fn foo(A { .. }: A) {}
+"#,
+ r#"
+struct Inner;
+struct A(Inner);
+fn foo(A(..): A) {}
+"#,
+ );
+
+ check_assist(
+ convert_named_struct_to_tuple_struct,
+ r#"
+struct Inner;
+struct A$0 { inner: Inner, extra: Inner }
+fn foo(A { inner, .. }: A) {}
+"#,
+ r#"
+struct Inner;
+struct A(Inner, Inner);
+fn foo(A(inner, ..): A) {}
+"#,
+ );
+ }
+
+ #[test]
fn convert_simple_struct_cursor_on_visibility_keyword() {
check_assist(
convert_named_struct_to_tuple_struct,
diff --git a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index ae13f83..7f4fb4c 100644
--- a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -75,8 +75,8 @@
let let_chains = flat_let_chain(cond);
- let then_block = if_expr.then_branch()?;
- let then_block = then_block.stmt_list()?;
+ let then_branch = if_expr.then_branch()?;
+ let then_block = then_branch.stmt_list()?;
let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
@@ -84,17 +84,8 @@
return None;
}
- // FIXME: This relies on untyped syntax tree and casts to much. It should be
- // rewritten to use strongly-typed APIs.
-
// check for early return and continue
- let first_in_then_block = then_block.syntax().first_child()?;
- if ast::ReturnExpr::can_cast(first_in_then_block.kind())
- || ast::ContinueExpr::can_cast(first_in_then_block.kind())
- || first_in_then_block
- .children()
- .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
- {
+ if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) {
return None;
}
@@ -255,20 +246,25 @@
fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
let mut chains = vec![];
+ let mut reduce_cond = |rhs| {
+ if !matches!(rhs, ast::Expr::LetExpr(_))
+ && let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_)))
+ {
+ chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
+ } else {
+ chains.push(rhs);
+ }
+ };
while let ast::Expr::BinExpr(bin_expr) = &expr
&& bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
&& let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
{
- if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) {
- chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
- } else {
- chains.push(rhs);
- }
+ reduce_cond(rhs);
expr = lhs;
}
- chains.push(expr);
+ reduce_cond(expr);
chains.reverse();
chains
}
@@ -284,6 +280,17 @@
}
}
+fn is_early_block(then_block: &ast::StmtList) -> bool {
+ let is_early_expr =
+ |expr| matches!(expr, ast::Expr::ReturnExpr(_) | ast::Expr::ContinueExpr(_));
+ let into_expr = |stmt| match stmt {
+ ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(),
+ _ => None,
+ };
+ then_block.tail_expr().is_some_and(is_early_expr)
+ || then_block.statements().filter_map(into_expr).any(is_early_expr)
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -554,6 +561,93 @@
}
"#,
);
+
+ check_assist(
+ convert_to_guarded_return,
+ r#"
+fn main() {
+ if$0 let Ok(x) = Err(92)
+ && let Ok(y) = Ok(37)
+ && x < 30
+ && let Some(y) = Some(8)
+ {
+ foo(x, y);
+ }
+}
+"#,
+ r#"
+fn main() {
+ let Ok(x) = Err(92) else { return };
+ let Ok(y) = Ok(37) else { return };
+ if x >= 30 {
+ return;
+ }
+ let Some(y) = Some(8) else { return };
+ foo(x, y);
+}
+"#,
+ );
+
+ check_assist(
+ convert_to_guarded_return,
+ r#"
+fn main() {
+ if$0 cond
+ && let Ok(x) = Err(92)
+ && let Ok(y) = Ok(37)
+ && x < 30
+ && let Some(y) = Some(8)
+ {
+ foo(x, y);
+ }
+}
+"#,
+ r#"
+fn main() {
+ if !cond {
+ return;
+ }
+ let Ok(x) = Err(92) else { return };
+ let Ok(y) = Ok(37) else { return };
+ if x >= 30 {
+ return;
+ }
+ let Some(y) = Some(8) else { return };
+ foo(x, y);
+}
+"#,
+ );
+
+ check_assist(
+ convert_to_guarded_return,
+ r#"
+fn main() {
+ if$0 cond
+ && foo()
+ && let Ok(x) = Err(92)
+ && let Ok(y) = Ok(37)
+ && x < 30
+ && let Some(y) = Some(8)
+ {
+ foo(x, y);
+ }
+}
+"#,
+ r#"
+fn main() {
+ if !(cond && foo()) {
+ return;
+ }
+ let Ok(x) = Err(92) else { return };
+ let Ok(y) = Ok(37) else { return };
+ if x >= 30 {
+ return;
+ }
+ let Some(y) = Some(8) else { return };
+ foo(x, y);
+}
+"#,
+ );
}
#[test]
diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 3d78895..61d8449 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -154,14 +154,7 @@
ast::TupleStructPat(tuple_struct_pat) => {
Some(make.record_pat_with_fields(
tuple_struct_pat.path()?,
- ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
- |(pat, name)| {
- ast::make::record_pat_field(
- ast::make::name_ref(&name.to_string()),
- pat,
- )
- },
- ), None),
+ generate_record_pat_list(&tuple_struct_pat, names),
).syntax().clone())
},
// for tuple struct creations like Foo(42)
@@ -284,6 +277,24 @@
.collect()
}
+fn generate_record_pat_list(
+ pat: &ast::TupleStructPat,
+ names: &[ast::Name],
+) -> ast::RecordPatFieldList {
+ let pure_fields = pat.fields().filter(|p| !matches!(p, ast::Pat::RestPat(_)));
+ let rest_len = names.len().saturating_sub(pure_fields.clone().count());
+ let rest_pat = pat.fields().find_map(|p| ast::RestPat::cast(p.syntax().clone()));
+ let rest_idx =
+ pat.fields().position(|p| ast::RestPat::can_cast(p.syntax().kind())).unwrap_or(names.len());
+ let before_rest = pat.fields().zip(names).take(rest_idx);
+ let after_rest = pure_fields.zip(names.iter().skip(rest_len)).skip(rest_idx);
+
+ let fields = before_rest
+ .chain(after_rest)
+ .map(|(pat, name)| ast::make::record_pat_field(ast::make::name_ref(&name.text()), pat));
+ ast::make::record_pat_field_list(fields, rest_pat)
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -359,6 +370,43 @@
}
#[test]
+ fn convert_struct_and_rest_pat() {
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+struct Inner;
+struct A$0(Inner);
+fn foo(A(..): A) {}
+"#,
+ r#"
+struct Inner;
+struct A { field1: Inner }
+fn foo(A { .. }: A) {}
+"#,
+ );
+
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X$0(A, B, C, D);
+fn foo(X(a, .., d): X) {}
+"#,
+ r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X { field1: A, field2: B, field3: C, field4: D }
+fn foo(X { field1: a, field4: d, .. }: X) {}
+"#,
+ );
+ }
+
+ #[test]
fn convert_simple_struct_cursor_on_struct_keyword() {
check_assist(
convert_tuple_struct_to_named_struct,
diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index f09389f..e2afc0b 100644
--- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -7,6 +7,7 @@
};
use itertools::Itertools;
use syntax::{
+ T,
ast::{self, AstNode, FieldExpr, HasName, IdentPat, make},
ted,
};
@@ -179,6 +180,11 @@
.map(|name| ast::Pat::from(make::ident_pat(is_ref, is_mut, make::name(name))));
make::tuple_pat(fields).clone_for_update()
};
+ let is_shorthand_field = ident_pat
+ .name()
+ .as_ref()
+ .and_then(ast::RecordPatField::for_field_name)
+ .is_some_and(|field| field.colon_token().is_none());
if let Some(cap) = ctx.config.snippet_cap {
// place cursor on first tuple name
@@ -190,12 +196,13 @@
}
}
- AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern }
+ AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern, is_shorthand_field }
}
struct AssignmentEdit {
ident_pat: ast::IdentPat,
tuple_pat: ast::TuplePat,
in_sub_pattern: bool,
+ is_shorthand_field: bool,
}
impl AssignmentEdit {
@@ -203,6 +210,9 @@
// with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
if self.in_sub_pattern {
self.ident_pat.set_pat(Some(self.tuple_pat.into()))
+ } else if self.is_shorthand_field {
+ ted::insert(ted::Position::after(self.ident_pat.syntax()), self.tuple_pat.syntax());
+ ted::insert_raw(ted::Position::after(self.ident_pat.syntax()), make::token(T![:]));
} else {
ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax())
}
@@ -800,6 +810,48 @@
}
#[test]
+ fn in_record_shorthand_field() {
+ check_assist(
+ assist,
+ r#"
+struct S { field: (i32, i32) }
+fn main() {
+ let S { $0field } = S { field: (2, 3) };
+ let v = field.0 + field.1;
+}
+ "#,
+ r#"
+struct S { field: (i32, i32) }
+fn main() {
+ let S { field: ($0_0, _1) } = S { field: (2, 3) };
+ let v = _0 + _1;
+}
+ "#,
+ )
+ }
+
+ #[test]
+ fn in_record_field() {
+ check_assist(
+ assist,
+ r#"
+struct S { field: (i32, i32) }
+fn main() {
+ let S { field: $0t } = S { field: (2, 3) };
+ let v = t.0 + t.1;
+}
+ "#,
+ r#"
+struct S { field: (i32, i32) }
+fn main() {
+ let S { field: ($0_0, _1) } = S { field: (2, 3) };
+ let v = _0 + _1;
+}
+ "#,
+ )
+ }
+
+ #[test]
fn in_nested_tuple() {
check_assist(
assist,
diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs
index dad19bf..a17ae48 100644
--- a/crates/ide-assists/src/handlers/extract_module.rs
+++ b/crates/ide-assists/src/handlers/extract_module.rs
@@ -1,4 +1,4 @@
-use std::ops::RangeInclusive;
+use std::{iter::once, ops::RangeInclusive};
use hir::{HasSource, ModuleSource};
use ide_db::{
@@ -63,19 +63,6 @@
syntax::NodeOrToken::Token(t) => t.parent()?,
};
- //If the selection is inside impl block, we need to place new module outside impl block,
- //as impl blocks cannot contain modules
-
- let mut impl_parent: Option<ast::Impl> = None;
- let mut impl_child_count: usize = 0;
- if let Some(parent_assoc_list) = node.parent()
- && let Some(parent_impl) = parent_assoc_list.parent()
- && let Some(impl_) = ast::Impl::cast(parent_impl)
- {
- impl_child_count = parent_assoc_list.children().count();
- impl_parent = Some(impl_);
- }
-
let mut curr_parent_module: Option<ast::Module> = None;
if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
curr_parent_module = ast::Module::cast(mod_syn_opt);
@@ -94,7 +81,22 @@
return None;
}
- let old_item_indent = module.body_items[0].indent_level();
+ let mut old_item_indent = module.body_items[0].indent_level();
+ let old_items: Vec<_> = module.use_items.iter().chain(&module.body_items).cloned().collect();
+
+ // If the selection is inside impl block, we need to place new module outside impl block,
+ // as impl blocks cannot contain modules
+
+ let mut impl_parent: Option<ast::Impl> = None;
+ let mut impl_child_count: usize = 0;
+ if let Some(parent_assoc_list) = module.body_items[0].syntax().parent()
+ && let Some(parent_impl) = parent_assoc_list.parent()
+ && let Some(impl_) = ast::Impl::cast(parent_impl)
+ {
+ impl_child_count = parent_assoc_list.children().count();
+ old_item_indent = impl_.indent_level();
+ impl_parent = Some(impl_);
+ }
acc.add(
AssistId::refactor_extract("extract_module"),
@@ -127,7 +129,7 @@
let import_items = module.resolve_imports(curr_parent_module, ctx);
module.change_visibility(record_fields);
- let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string();
+ let module_def = generate_module_def(&impl_parent, &module).indent(old_item_indent);
let mut usages_to_be_processed_for_cur_file = vec![];
for (file_id, usages) in usages_to_be_processed {
@@ -149,27 +151,32 @@
if let Some(impl_) = impl_parent {
// Remove complete impl block if it has only one child (as such it will be empty
// after deleting that child)
- let node_to_be_removed = if impl_child_count == 1 {
- impl_.syntax()
+ let nodes_to_be_removed = if impl_child_count == old_items.len() {
+ vec![impl_.syntax()]
} else {
//Remove selected node
- &node
+ old_items.iter().map(|it| it.syntax()).collect()
};
- builder.delete(node_to_be_removed.text_range());
- // Remove preceding indentation from node
- if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
- builder.delete(range);
+ for node_to_be_removed in nodes_to_be_removed {
+ builder.delete(node_to_be_removed.text_range());
+ // Remove preceding indentation from node
+ if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
+ builder.delete(range);
+ }
}
- builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
+ builder.insert(
+ impl_.syntax().text_range().end(),
+ format!("\n\n{old_item_indent}{module_def}"),
+ );
} else {
for import_item in import_items {
if !module_text_range.contains_range(import_item) {
builder.delete(import_item);
}
}
- builder.replace(module_text_range, module_def)
+ builder.replace(module_text_range, module_def.to_string())
}
},
)
@@ -177,34 +184,35 @@
fn generate_module_def(
parent_impl: &Option<ast::Impl>,
- module: Module,
- old_indent: IndentLevel,
+ Module { name, body_items, use_items }: &Module,
) -> ast::Module {
- let Module { name, body_items, use_items } = module;
- let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) {
+ let items: Vec<_> = if let Some(impl_) = parent_impl.as_ref()
+ && let Some(self_ty) = impl_.self_ty()
+ {
let assoc_items = body_items
- .into_iter()
+ .iter()
.map(|item| item.syntax().clone())
.filter_map(ast::AssocItem::cast)
.map(|it| it.indent(IndentLevel(1)))
.collect_vec();
- let assoc_item_list = make::assoc_item_list(Some(assoc_items));
- let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list));
+ let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update();
+ let impl_ = impl_.reset_indent();
+ ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax());
// Add the import for enum/struct corresponding to given impl block
let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax());
- let mut module_body_items = use_items;
- module_body_items.insert(0, use_impl);
- module_body_items.push(ast::Item::Impl(impl_));
- module_body_items
+ once(use_impl)
+ .chain(use_items.iter().cloned())
+ .chain(once(ast::Item::Impl(impl_)))
+ .collect()
} else {
- [use_items, body_items].concat()
+ use_items.iter().chain(body_items).cloned().collect()
};
let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec();
let module_body = make::item_list(Some(items));
let module_name = make::name(name);
- make::mod_(module_name, Some(module_body)).indent(old_indent)
+ make::mod_(module_name, Some(module_body))
}
fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item {
@@ -1400,28 +1408,54 @@
fn test_if_inside_impl_block_generate_module_outside() {
check_assist(
extract_module,
- r"
- struct A {}
+ r"struct A {}
impl A {
-$0fn foo() {}$0
+ $0fn foo() {}$0
fn bar() {}
}
",
- r"
- struct A {}
+ r"struct A {}
impl A {
fn bar() {}
}
-mod modname {
- use super::A;
+ mod modname {
+ use super::A;
- impl A {
- pub(crate) fn foo() {}
- }
-}
+ impl A {
+ pub(crate) fn foo() {}
+ }
+ }
+ ",
+ );
+
+ check_assist(
+ extract_module,
+ r"struct A {}
+
+ impl A {
+ $0fn foo() {}
+ fn bar() {}$0
+ fn baz() {}
+ }
+ ",
+ r"struct A {}
+
+ impl A {
+ fn baz() {}
+ }
+
+ mod modname {
+ use super::A;
+
+ impl A {
+ pub(crate) fn foo() {}
+
+ pub(crate) fn bar() {}
+ }
+ }
",
)
}
@@ -1430,27 +1464,25 @@
fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() {
check_assist(
extract_module,
- r"
- struct A {}
+ r"struct A {}
struct B {}
impl A {
$0fn foo(x: B) {}$0
}
",
- r"
- struct A {}
+ r"struct A {}
struct B {}
-mod modname {
- use super::A;
+ mod modname {
+ use super::A;
- use super::B;
+ use super::B;
- impl A {
- pub(crate) fn foo(x: B) {}
- }
-}
+ impl A {
+ pub(crate) fn foo(x: B) {}
+ }
+ }
",
)
}
diff --git a/crates/ide-assists/src/handlers/flip_binexpr.rs b/crates/ide-assists/src/handlers/flip_binexpr.rs
index 247e810..8f2306e 100644
--- a/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -1,6 +1,7 @@
use syntax::{
SyntaxKind, T,
- ast::{self, AstNode, BinExpr, syntax_factory::SyntaxFactory},
+ ast::{self, AstNode, BinExpr, RangeItem, syntax_factory::SyntaxFactory},
+ syntax_editor::Position,
};
use crate::{AssistContext, AssistId, Assists};
@@ -87,6 +88,74 @@
}
}
+// Assist: flip_range_expr
+//
+// Flips operands of a range expression.
+//
+// ```
+// fn main() {
+// let _ = 90..$02;
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// let _ = 2..90;
+// }
+// ```
+// ---
+// ```
+// fn main() {
+// let _ = 90..$0;
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// let _ = ..90;
+// }
+// ```
+pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let range_expr = ctx.find_node_at_offset::<ast::RangeExpr>()?;
+ let op = range_expr.op_token()?;
+ let start = range_expr.start();
+ let end = range_expr.end();
+
+ if !op.text_range().contains_range(ctx.selection_trimmed()) {
+ return None;
+ }
+ if start.is_none() && end.is_none() {
+ return None;
+ }
+
+ acc.add(
+ AssistId::refactor_rewrite("flip_range_expr"),
+ "Flip range expression",
+ op.text_range(),
+ |builder| {
+ let mut edit = builder.make_editor(range_expr.syntax());
+
+ match (start, end) {
+ (Some(start), Some(end)) => {
+ edit.replace(start.syntax(), end.syntax());
+ edit.replace(end.syntax(), start.syntax());
+ }
+ (Some(start), None) => {
+ edit.delete(start.syntax());
+ edit.insert(Position::after(&op), start.syntax().clone_for_update());
+ }
+ (None, Some(end)) => {
+ edit.delete(end.syntax());
+ edit.insert(Position::before(&op), end.syntax().clone_for_update());
+ }
+ (None, None) => (),
+ }
+
+ builder.add_file_edits(ctx.vfs_file_id(), edit);
+ },
+ )
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index 6c302a2..a1ec763 100644
--- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -5,9 +5,10 @@
RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast,
imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
};
+use syntax::syntax_editor::{Element, Position};
use syntax::{
TokenText,
- ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent},
+ ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit},
};
use crate::{
@@ -111,9 +112,8 @@
false,
false,
)
- .clone_for_update();
+ .indent(1.into());
- fn_.indent(1.into());
let cfg_attrs = strukt
.attrs()
.filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
@@ -129,16 +129,25 @@
make::ty("From"),
ty.clone(),
None,
- ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)),
+ ty_where_clause.map(|wc| wc.reset_indent()),
None,
)
.clone_for_update();
impl_.get_or_create_assoc_item_list().add_item(fn_.into());
+ let impl_ = impl_.indent(indent);
- impl_.reindent_to(indent);
+ let mut edit = builder.make_editor(strukt.syntax());
- builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
+ edit.insert_all(
+ Position::after(strukt.syntax()),
+ vec![
+ make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(),
+ impl_.syntax().syntax_element(),
+ ],
+ );
+
+ builder.add_file_edits(ctx.vfs_file_id(), edit);
},
)
}
diff --git a/crates/ide-assists/src/handlers/invert_if.rs b/crates/ide-assists/src/handlers/invert_if.rs
index 7576d2f..bf82d8d 100644
--- a/crates/ide-assists/src/handlers/invert_if.rs
+++ b/crates/ide-assists/src/handlers/invert_if.rs
@@ -27,7 +27,9 @@
// }
// ```
pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
- let if_keyword = ctx.find_token_syntax_at_offset(T![if])?;
+ let if_keyword = ctx
+ .find_token_syntax_at_offset(T![if])
+ .or_else(|| ctx.find_token_syntax_at_offset(T![else]))?;
let expr = ast::IfExpr::cast(if_keyword.parent()?)?;
let if_range = if_keyword.text_range();
let cursor_in_range = if_range.contains_range(ctx.selection_trimmed());
@@ -112,6 +114,15 @@
}
#[test]
+ fn invert_if_on_else_keyword() {
+ check_assist(
+ invert_if,
+ "fn f() { if cond { 3 * 2 } e$0lse { 1 } }",
+ "fn f() { if !cond { 1 } else { 3 * 2 } }",
+ )
+ }
+
+ #[test]
fn invert_if_doesnt_apply_with_cursor_not_on_if() {
check_assist_not_applicable(invert_if, "fn f() { if !$0cond { 3 * 2 } else { 1 } }")
}
diff --git a/crates/ide-assists/src/handlers/remove_else_branches.rs b/crates/ide-assists/src/handlers/remove_else_branches.rs
new file mode 100644
index 0000000..6a02c37
--- /dev/null
+++ b/crates/ide-assists/src/handlers/remove_else_branches.rs
@@ -0,0 +1,90 @@
+use syntax::{AstNode, SyntaxKind, T, TextRange, ast};
+
+use crate::{AssistContext, AssistId, Assists};
+
+// Assist: remove_else_branches
+//
+// Removes the `else` keyword and else branches.
+//
+// ```
+// fn main() {
+// if true {
+// let _ = 2;
+// } $0else {
+// unreachable!();
+// }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// if true {
+// let _ = 2;
+// }
+// }
+// ```
+// ---
+// ```
+// fn main() {
+// let _x = 2 $0else { unreachable!() };
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// let _x = 2;
+// }
+// ```
+pub(crate) fn remove_else_branches(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let else_token = ctx.find_token_syntax_at_offset(T![else])?;
+ let else_branches = ctx
+ .find_node_at_range::<ast::IfExpr>()
+ .and_then(|if_expr| if_expr.else_branch()?.syntax().clone().into())
+ .or_else(|| {
+ ctx.find_node_at_range::<ast::LetStmt>()?
+ .let_else()?
+ .block_expr()?
+ .syntax()
+ .clone()
+ .into()
+ })?;
+
+ let target = TextRange::cover(else_token.text_range(), else_branches.text_range());
+ acc.add(
+ AssistId::refactor("remove_else_branches"),
+ "Remove `else` branches",
+ target,
+ |builder| {
+ let mut editor = builder.make_editor(&else_token.parent().unwrap());
+ match else_token.prev_token() {
+ Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
+ _ => (),
+ }
+ match else_token.next_token() {
+ Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
+ _ => (),
+ }
+ editor.delete(else_token);
+ editor.delete(else_branches);
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::tests::check_assist_not_applicable;
+
+ #[test]
+ fn test_remove_else_branches_not_on_else_token() {
+ check_assist_not_applicable(
+ remove_else_branches,
+ r#"
+fn main() {
+ let _x = 2 else {$0 unreachable!() };
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index f507cae..c57fd4d 100644
--- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -1,7 +1,7 @@
use ide_db::syntax_helpers::suggest_name;
use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
-use crate::{AssistContext, AssistId, Assists};
+use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain};
// Assist: replace_is_some_with_if_let_some
//
@@ -27,13 +27,11 @@
let if_expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
let cond = if_expr.condition()?;
+ let cond = cover_let_chain(cond, ctx.selection_trimmed())?;
let call_expr = match cond {
ast::Expr::MethodCallExpr(call) => call,
_ => return None,
};
- if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
- return None;
- }
let name_ref = call_expr.name_ref()?;
match name_ref.text().as_str() {
@@ -196,6 +194,63 @@
}
#[test]
+ fn replace_is_some_with_if_let_some_in_let_chain() {
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && x.is_som$0e() {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && let Some(${0:x1}) = x {}
+}
+"#,
+ );
+
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if x.is_som$0e() && cond {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if let Some(${0:x1}) = x && cond {}
+}
+"#,
+ );
+
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && x.is_som$0e() && cond {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && let Some(${0:x1}) = x && cond {}
+}
+"#,
+ );
+ }
+
+ #[test]
fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
check_assist_not_applicable(
replace_is_method_with_if_let_method,
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index 2977f8b..e9f2d68 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -201,6 +201,7 @@
mod qualify_path;
mod raw_string;
mod remove_dbg;
+ mod remove_else_branches;
mod remove_mut;
mod remove_parentheses;
mod remove_underscore;
@@ -284,6 +285,7 @@
extract_type_alias::extract_type_alias,
fix_visibility::fix_visibility,
flip_binexpr::flip_binexpr,
+ flip_binexpr::flip_range_expr,
flip_comma::flip_comma,
flip_or_pattern::flip_or_pattern,
flip_trait_bound::flip_trait_bound,
@@ -342,6 +344,7 @@
raw_string::remove_hash,
remove_dbg::remove_dbg,
remove_mut::remove_mut,
+ remove_else_branches::remove_else_branches,
remove_parentheses::remove_parentheses,
remove_underscore::remove_underscore,
remove_unused_imports::remove_unused_imports,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index c7ae441..a99fe8d 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -28,6 +28,25 @@
}
#[test]
+fn doctest_add_braces_1() {
+ check_doc_test(
+ "add_braces",
+ r#####"
+fn foo(n: i32) -> i32 {
+ let x =$0 n + 2;
+}
+"#####,
+ r#####"
+fn foo(n: i32) -> i32 {
+ let x = {
+ n + 2
+ };
+}
+"#####,
+ )
+}
+
+#[test]
fn doctest_add_explicit_enum_discriminant() {
check_doc_test(
"add_explicit_enum_discriminant",
@@ -1333,6 +1352,40 @@
}
#[test]
+fn doctest_flip_range_expr() {
+ check_doc_test(
+ "flip_range_expr",
+ r#####"
+fn main() {
+ let _ = 90..$02;
+}
+"#####,
+ r#####"
+fn main() {
+ let _ = 2..90;
+}
+"#####,
+ )
+}
+
+#[test]
+fn doctest_flip_range_expr_1() {
+ check_doc_test(
+ "flip_range_expr",
+ r#####"
+fn main() {
+ let _ = 90..$0;
+}
+"#####,
+ r#####"
+fn main() {
+ let _ = ..90;
+}
+"#####,
+ )
+}
+
+#[test]
fn doctest_flip_trait_bound() {
check_doc_test(
"flip_trait_bound",
@@ -2864,6 +2917,46 @@
}
#[test]
+fn doctest_remove_else_branches() {
+ check_doc_test(
+ "remove_else_branches",
+ r#####"
+fn main() {
+ if true {
+ let _ = 2;
+ } $0else {
+ unreachable!();
+ }
+}
+"#####,
+ r#####"
+fn main() {
+ if true {
+ let _ = 2;
+ }
+}
+"#####,
+ )
+}
+
+#[test]
+fn doctest_remove_else_branches_1() {
+ check_doc_test(
+ "remove_else_branches",
+ r#####"
+fn main() {
+ let _x = 2 $0else { unreachable!() };
+}
+"#####,
+ r#####"
+fn main() {
+ let _x = 2;
+}
+"#####,
+ )
+}
+
+#[test]
fn doctest_remove_hash() {
check_doc_test(
"remove_hash",
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 5a3c5a3..e43516f 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -1133,6 +1133,28 @@
tt_stack.pop().expect("parent token tree was closed before it was completed").1
}
+pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option<ast::Expr> {
+ if !expr.syntax().text_range().contains_range(range) {
+ return None;
+ }
+ loop {
+ let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr
+ && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
+ {
+ (bin_expr.rhs(), bin_expr.lhs())
+ } else {
+ (Some(expr), None)
+ };
+
+ if let Some(chain_expr) = chain_expr
+ && chain_expr.syntax().text_range().contains_range(range)
+ {
+ break Some(chain_expr);
+ }
+ expr = rest?;
+ }
+}
+
pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
let mut is_const = true;
preorder_expr(expr, &mut |ev| {
diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml
index 9bad21f..277d5df 100644
--- a/crates/ide-completion/Cargo.toml
+++ b/crates/ide-completion/Cargo.toml
@@ -28,6 +28,7 @@
# completions crate should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
hir.workspace = true
+macros.workspace = true
[dev-dependencies]
expect-test = "1.5.1"
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index b822f53..abae3cb 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -16,6 +16,7 @@
pub(crate) mod mod_;
pub(crate) mod pattern;
pub(crate) mod postfix;
+pub(crate) mod ra_fixture;
pub(crate) mod record;
pub(crate) mod snippet;
pub(crate) mod r#type;
@@ -74,6 +75,10 @@
self.buf.push(item)
}
+ fn add_many(&mut self, items: impl IntoIterator<Item = CompletionItem>) {
+ self.buf.extend(items)
+ }
+
fn add_opt(&mut self, item: Option<CompletionItem>) {
if let Some(item) = item {
self.buf.push(item)
@@ -106,6 +111,13 @@
}
}
+ pub(crate) fn add_type_keywords(&mut self, ctx: &CompletionContext<'_>) {
+ self.add_keyword_snippet(ctx, "fn", "fn($1)");
+ self.add_keyword_snippet(ctx, "dyn", "dyn $0");
+ self.add_keyword_snippet(ctx, "impl", "impl $0");
+ self.add_keyword_snippet(ctx, "for", "for<$1>");
+ }
+
pub(crate) fn add_super_keyword(
&mut self,
ctx: &CompletionContext<'_>,
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index e174b0c..297ce33 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -231,7 +231,7 @@
macro_rules! attrs {
// attributes applicable to all items
[@ { item $($tt:tt)* } {$($acc:tt)*}] => {
- attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "must_use", "no_mangle" })
+ attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "docinclude", "must_use", "no_mangle" })
};
// attributes applicable to all adts
[@ { adt $($tt:tt)* } {$($acc:tt)*}] => {
@@ -345,6 +345,7 @@
attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)),
+ attr(r#"doc = include_str!("…")"#, Some("docinclude"), Some(r#"doc = include_str!("$0")"#)),
attr("expect(…)", Some("expect"), Some("expect(${0:lint})")),
attr(
r#"export_name = "…""#,
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 72b245c..511b593 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -25,9 +25,7 @@
_ => return,
};
- let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. });
- let is_method_access_with_parens =
- matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+ let has_parens = matches!(dot_access.kind, DotAccessKind::Method);
let traits_in_scope = ctx.traits_in_scope();
// Suggest .await syntax for types that implement Future trait
@@ -48,7 +46,7 @@
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
}
- it @ DotAccessKind::Method { .. } => *it,
+ it @ DotAccessKind::Method => *it,
};
let dot_access = DotAccess {
receiver: dot_access.receiver.clone(),
@@ -67,8 +65,7 @@
acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
},
|acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
- is_field_access,
- is_method_access_with_parens,
+ has_parens,
);
complete_methods(ctx, &future_output, &traits_in_scope, |func| {
acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
@@ -82,8 +79,7 @@
receiver_ty,
|acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty),
|acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
- is_field_access,
- is_method_access_with_parens,
+ has_parens,
);
complete_methods(ctx, receiver_ty, &traits_in_scope, |func| {
acc.add_method(ctx, dot_access, func, None, None)
@@ -112,7 +108,7 @@
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
}
- it @ DotAccessKind::Method { .. } => *it,
+ it @ DotAccessKind::Method => *it,
};
let dot_access = DotAccess {
receiver: dot_access.receiver.clone(),
@@ -173,7 +169,6 @@
)
},
|acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty),
- true,
false,
);
complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| {
@@ -182,7 +177,7 @@
&DotAccess {
receiver: None,
receiver_ty: None,
- kind: DotAccessKind::Method { has_parens: false },
+ kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
ctx: DotAccessExprCtx {
in_block_expr: expr_ctx.in_block_expr,
in_breakable: expr_ctx.in_breakable,
@@ -201,15 +196,13 @@
receiver: &hir::Type<'_>,
mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>),
mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>),
- is_field_access: bool,
- is_method_access_with_parens: bool,
+ has_parens: bool,
) {
let mut seen_names = FxHashSet::default();
for receiver in receiver.autoderef(ctx.db) {
for (field, ty) in receiver.fields(ctx.db) {
if seen_names.insert(field.name(ctx.db))
- && (is_field_access
- || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure())))
+ && (!has_parens || ty.is_fn() || ty.is_closure())
{
named_field(acc, field, ty);
}
@@ -218,8 +211,7 @@
// Tuples are always the last type in a deref chain, so just check if the name is
// already seen without inserting into the hashset.
if !seen_names.contains(&hir::Name::new_tuple_field(i))
- && (is_field_access
- || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure())))
+ && (!has_parens || ty.is_fn() || ty.is_closure())
{
// Tuple fields are always public (tuple struct fields are handled above).
tuple_index(acc, i, ty);
@@ -1364,18 +1356,71 @@
r#"
struct Foo { baz: fn() }
impl Foo {
- fn bar<T>(self, t: T): T { t }
+ fn bar<T>(self, t: T) -> T { t }
}
fn baz() {
let foo = Foo{ baz: || {} };
- foo.ba$0::<>;
+ foo.ba$0;
}
"#,
expect![[r#"
- me bar(…) fn(self, T)
+ fd baz fn()
+ me bar(…) fn(self, T) -> T
"#]],
);
+
+ check_edit(
+ "baz",
+ r#"
+struct Foo { baz: fn() }
+impl Foo {
+ fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+ let foo = Foo{ baz: || {} };
+ foo.ba$0;
+}
+"#,
+ r#"
+struct Foo { baz: fn() }
+impl Foo {
+ fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+ let foo = Foo{ baz: || {} };
+ (foo.baz)();
+}
+"#,
+ );
+
+ check_edit(
+ "bar",
+ r#"
+struct Foo { baz: fn() }
+impl Foo {
+ fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+ let foo = Foo{ baz: || {} };
+ foo.ba$0;
+}
+"#,
+ r#"
+struct Foo { baz: fn() }
+impl Foo {
+ fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+ let foo = Foo{ baz: || {} };
+ foo.bar(${1:t})$0;
+}
+"#,
+ );
}
#[test]
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 0ce81d0..dcddc24 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -42,6 +42,11 @@
}
}
+ if pattern_ctx.after_if_expr {
+ add_keyword("else", "else {\n $0\n}");
+ add_keyword("else if", "else if $1 {\n $0\n}");
+ }
+
if pattern_ctx.record_pat.is_some() {
return;
}
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 73cbe3f..ab3f619 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -43,7 +43,7 @@
DotAccessKind::Field { receiver_is_ambiguous_float_literal } => {
receiver_is_ambiguous_float_literal
}
- DotAccessKind::Method { .. } => false,
+ DotAccessKind::Method => false,
},
),
_ => return,
@@ -460,6 +460,8 @@
ast::MatchGuard(guard) => guard.condition()? == *it,
ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&])
.then(|| is_in_condition(&bin_expr.into()))?,
+ ast::Expr(expr) => (expr.syntax().text_range().start() == it.syntax().text_range().start())
+ .then(|| is_in_condition(&expr))?,
_ => return None,
} })
})
diff --git a/crates/ide-completion/src/completions/ra_fixture.rs b/crates/ide-completion/src/completions/ra_fixture.rs
new file mode 100644
index 0000000..b44c907
--- /dev/null
+++ b/crates/ide-completion/src/completions/ra_fixture.rs
@@ -0,0 +1,113 @@
+//! Injected completions for `#[rust_analyzer::rust_fixture]`.
+
+use hir::FilePositionWrapper;
+use ide_db::{
+ impl_empty_upmap_from_ra_fixture,
+ ra_fixture::{RaFixtureAnalysis, UpmapFromRaFixture},
+};
+use syntax::ast;
+
+use crate::{
+ CompletionItemKind, CompletionItemRefMode, CompletionRelevance, completions::Completions,
+ context::CompletionContext, item::CompletionItemLabel,
+};
+
+pub(crate) fn complete_ra_fixture(
+ acc: &mut Completions,
+ ctx: &CompletionContext<'_>,
+ original: &ast::String,
+ expanded: &ast::String,
+) -> Option<()> {
+ let analysis = RaFixtureAnalysis::analyze_ra_fixture(
+ &ctx.sema,
+ original.clone(),
+ expanded,
+ ctx.config.minicore,
+ &mut |_| {},
+ )?;
+ let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?;
+ let completions = hir::attach_db_allow_change(&analysis.db, || {
+ crate::completions(
+ &analysis.db,
+ ctx.config,
+ FilePositionWrapper { file_id: virtual_file_id, offset: virtual_offset },
+ ctx.trigger_character,
+ )
+ })?;
+ let completions =
+ completions.upmap_from_ra_fixture(&analysis, virtual_file_id, ctx.position.file_id).ok()?;
+ acc.add_many(completions);
+ Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(
+ CompletionItemLabel,
+ CompletionItemKind,
+ CompletionRelevance,
+ CompletionItemRefMode,
+);
+
+#[cfg(test)]
+mod tests {
+ use expect_test::expect;
+
+ use crate::tests::check;
+
+ #[test]
+ fn it_works() {
+ check(
+ r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+ fixture(r#"
+fn complete_me() {}
+
+fn baz() {
+ let foo_bar_baz = 123;
+ f$0
+}
+ "#);
+}
+ "##,
+ expect![[r#"
+ fn baz() fn()
+ fn complete_me() fn()
+ lc foo_bar_baz i32
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ }
+}
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 28b324d..bfa5670 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -179,6 +179,33 @@
}
#[test]
+ fn literal_struct_completion_shorthand() {
+ check_edit(
+ "FooDesc{}",
+ r#"
+struct FooDesc { pub bar: bool, n: i32 }
+
+fn create_foo(foo_desc: &FooDesc) -> () { () }
+
+fn baz() {
+ let bar = true;
+ let foo = create_foo(&$0);
+}
+ "#,
+ r#"
+struct FooDesc { pub bar: bool, n: i32 }
+
+fn create_foo(foo_desc: &FooDesc) -> () { () }
+
+fn baz() {
+ let bar = true;
+ let foo = create_foo(&FooDesc { bar$1, n: ${2:()} }$0);
+}
+ "#,
+ )
+ }
+
+ #[test]
fn enum_variant_no_snippets() {
let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG };
// tuple variant
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 3112462..3465b73 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -205,6 +205,7 @@
};
acc.add_nameref_keywords_with_colon(ctx);
+ acc.add_type_keywords(ctx);
ctx.process_all_names(&mut |name, def, doc_aliases| {
if scope_def_applicable(def) {
acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index b7367cb..5623257 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -6,13 +6,13 @@
use hir::FindPathConfig;
use ide_db::{
- SnippetCap,
+ MiniCore, SnippetCap,
imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
};
use crate::{CompletionFieldsToResolve, snippet::Snippet};
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug)]
pub struct CompletionConfig<'a> {
pub enable_postfix_completions: bool,
pub enable_imports_on_the_fly: bool,
@@ -35,6 +35,7 @@
pub fields_to_resolve: CompletionFieldsToResolve,
pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>,
pub exclude_traits: &'a [String],
+ pub minicore: MiniCore<'a>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4032329..2f166b7 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -279,6 +279,7 @@
pub(crate) param_ctx: Option<ParamContext>,
pub(crate) has_type_ascription: bool,
pub(crate) should_suggest_name: bool,
+ pub(crate) after_if_expr: bool,
pub(crate) parent_pat: Option<ast::Pat>,
pub(crate) ref_token: Option<SyntaxToken>,
pub(crate) mut_token: Option<SyntaxToken>,
@@ -405,9 +406,7 @@
/// like `0.$0`
receiver_is_ambiguous_float_literal: bool,
},
- Method {
- has_parens: bool,
- },
+ Method,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -440,6 +439,7 @@
pub(crate) config: &'a CompletionConfig<'a>,
pub(crate) position: FilePosition,
+ pub(crate) trigger_character: Option<char>,
/// The token before the cursor, in the original file.
pub(crate) original_token: SyntaxToken,
/// The token before the cursor, in the macro-expanded file.
@@ -703,6 +703,7 @@
db: &'db RootDatabase,
position @ FilePosition { file_id, offset }: FilePosition,
config: &'db CompletionConfig<'db>,
+ trigger_character: Option<char>,
) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
let _p = tracing::info_span!("CompletionContext::new").entered();
let sema = Semantics::new(db);
@@ -871,6 +872,7 @@
db,
config,
position,
+ trigger_character,
original_token,
token,
krate,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 873ecef..b3d9ff0 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -891,44 +891,53 @@
return Some(make_res(kind));
}
+ let field_expr_handle = |receiver, node| {
+ let receiver = find_opt_node_in_file(original_file, receiver);
+ let receiver_is_ambiguous_float_literal = match &receiver {
+ Some(ast::Expr::Literal(l)) => matches! {
+ l.kind(),
+ ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.'))
+ },
+ _ => false,
+ };
+
+ let receiver_is_part_of_indivisible_expression = match &receiver {
+ Some(ast::Expr::IfExpr(_)) => {
+ let next_token_kind =
+ next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind());
+ next_token_kind == Some(SyntaxKind::ELSE_KW)
+ }
+ _ => false,
+ };
+ if receiver_is_part_of_indivisible_expression {
+ return None;
+ }
+
+ let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
+ if receiver_is_ambiguous_float_literal {
+ // `123.|` is parsed as a float but should actually be an integer.
+ always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
+ receiver_ty =
+ Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
+ }
+
+ let kind = NameRefKind::DotAccess(DotAccess {
+ receiver_ty,
+ kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
+ receiver,
+ ctx: DotAccessExprCtx {
+ in_block_expr: is_in_block(node),
+ in_breakable: is_in_breakable(node).unzip().0,
+ },
+ });
+ Some(make_res(kind))
+ };
+
let segment = match_ast! {
match parent {
ast::PathSegment(segment) => segment,
ast::FieldExpr(field) => {
- let receiver = find_opt_node_in_file(original_file, field.expr());
- let receiver_is_ambiguous_float_literal = match &receiver {
- Some(ast::Expr::Literal(l)) => matches! {
- l.kind(),
- ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.'))
- },
- _ => false,
- };
-
- let receiver_is_part_of_indivisible_expression = match &receiver {
- Some(ast::Expr::IfExpr(_)) => {
- let next_token_kind = next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind());
- next_token_kind == Some(SyntaxKind::ELSE_KW)
- },
- _ => false
- };
- if receiver_is_part_of_indivisible_expression {
- return None;
- }
-
- let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
- if receiver_is_ambiguous_float_literal {
- // `123.|` is parsed as a float but should actually be an integer.
- always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
- receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
- }
-
- let kind = NameRefKind::DotAccess(DotAccess {
- receiver_ty,
- kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
- receiver,
- ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 }
- });
- return Some(make_res(kind));
+ return field_expr_handle(field.expr(), field.syntax());
},
ast::ExternCrate(_) => {
let kind = NameRefKind::ExternCrate;
@@ -937,9 +946,12 @@
ast::MethodCallExpr(method) => {
let receiver = find_opt_node_in_file(original_file, method.receiver());
let has_parens = has_parens(&method);
+ if !has_parens && let Some(res) = field_expr_handle(method.receiver(), method.syntax()) {
+ return Some(res)
+ }
let kind = NameRefKind::DotAccess(DotAccess {
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
- kind: DotAccessKind::Method { has_parens },
+ kind: DotAccessKind::Method,
receiver,
ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 }
});
@@ -987,10 +999,6 @@
}
}
};
- let after_if_expr = |node: SyntaxNode| {
- let prev_expr = prev_expr(node);
- matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
- };
let after_incomplete_let = |node: SyntaxNode| {
prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
};
@@ -1230,7 +1238,7 @@
let it = expr.syntax();
let in_block_expr = is_in_block(it);
let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
- let after_if_expr = after_if_expr(it.clone());
+ let after_if_expr = is_after_if_expr(it.clone());
let ref_expr_parent =
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
@@ -1751,6 +1759,7 @@
param_ctx,
has_type_ascription,
should_suggest_name,
+ after_if_expr: is_after_if_expr(pat.syntax().clone()),
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
mut_token,
ref_token,
@@ -1890,11 +1899,49 @@
}
fn is_in_block(node: &SyntaxNode) -> bool {
+ if has_in_newline_expr_first(node) {
+ return true;
+ };
node.parent()
.map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()))
.unwrap_or(false)
}
+/// Similar to `has_parens`, heuristic sensing incomplete statement before ambiguous `Expr`
+///
+/// Heuristic:
+///
+/// If the `PathExpr` is left part of the `Expr` and there is a newline after the `PathExpr`,
+/// it is considered that the `PathExpr` is not part of the `Expr`.
+fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
+ if ast::PathExpr::can_cast(node.kind())
+ && let Some(NodeOrToken::Token(next)) = node.next_sibling_or_token()
+ && next.kind() == SyntaxKind::WHITESPACE
+ && next.text().contains('\n')
+ && let Some(stmt_like) = node
+ .ancestors()
+ .take_while(|it| it.text_range().start() == node.text_range().start())
+ .filter_map(Either::<ast::ExprStmt, ast::Expr>::cast)
+ .last()
+ {
+ stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some()
+ } else {
+ false
+ }
+}
+
+fn is_after_if_expr(node: SyntaxNode) -> bool {
+ let node = match node.parent().and_then(Either::<ast::ExprStmt, ast::MatchArm>::cast) {
+ Some(stmt) => stmt.syntax().clone(),
+ None => node,
+ };
+ let prev_sibling =
+ non_trivia_sibling(node.into(), Direction::Prev).and_then(NodeOrToken::into_node);
+ iter::successors(prev_sibling, |it| it.last_child_or_token()?.into_node())
+ .find_map(ast::IfExpr::cast)
+ .is_some()
+}
+
fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
let mut token = match e.into() {
SyntaxElement::Node(n) => n.last_token()?,
diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs
index e798f3b..51d28bd 100644
--- a/crates/ide-completion/src/context/tests.rs
+++ b/crates/ide-completion/src/context/tests.rs
@@ -10,7 +10,7 @@
let (db, pos) = position(ra_fixture);
let config = TEST_CONFIG;
let (completion_context, _analysis) =
- hir::attach_db(&db, || CompletionContext::new(&db, pos, &config).unwrap());
+ hir::attach_db(&db, || CompletionContext::new(&db, pos, &config, None).unwrap());
let ty = completion_context
.expected_type
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index 5fb9dc9..303c712 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -9,6 +9,7 @@
imports::import_assets::LocatedImport,
};
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use smallvec::SmallVec;
use stdx::{format_to, impl_from, never};
use syntax::{Edition, SmolStr, TextRange, TextSize, format_smolstr};
@@ -23,7 +24,7 @@
///
/// It is basically a POD with various properties. To construct a [`CompletionItem`],
/// use [`Builder::new`] method and the [`Builder`] struct.
-#[derive(Clone)]
+#[derive(Clone, UpmapFromRaFixture)]
#[non_exhaustive]
pub struct CompletionItem {
/// Label in the completion pop up which identifies completion.
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index a70a113..8a0aaf3 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -187,7 +187,7 @@
position: FilePosition,
trigger_character: Option<char>,
) -> Option<Vec<CompletionItem>> {
- let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
+ let (ctx, analysis) = &CompletionContext::new(db, position, config, trigger_character)?;
let mut completions = Completions::default();
// prevent `(` from triggering unwanted completion noise
@@ -241,6 +241,7 @@
completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
completions::format_string::format_string(acc, ctx, original, expanded);
completions::env_vars::complete_cargo_env_vars(acc, ctx, original, expanded);
+ completions::ra_fixture::complete_ra_fixture(acc, ctx, original, expanded);
}
CompletionAnalysis::UnexpandedAttrTT {
colon_prefix,
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 094e679..c0f09e1 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -171,8 +171,7 @@
builder.insert(receiver.syntax().text_range().start(), "(".to_owned());
builder.insert(ctx.source_range().end(), ")".to_owned());
- let is_parens_needed =
- !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+ let is_parens_needed = !matches!(dot_access.kind, DotAccessKind::Method);
if is_parens_needed {
builder.insert(ctx.source_range().end(), "()".to_owned());
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index c466019..3235323 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -93,8 +93,8 @@
has_call_parens,
..
}) => (false, has_call_parens, ctx.completion.config.snippet_cap),
- FuncKind::Method(&DotAccess { kind: DotAccessKind::Method { has_parens }, .. }, _) => {
- (true, has_parens, ctx.completion.config.snippet_cap)
+ FuncKind::Method(&DotAccess { kind: DotAccessKind::Method, .. }, _) => {
+ (true, true, ctx.completion.config.snippet_cap)
}
FuncKind::Method(DotAccess { kind: DotAccessKind::Field { .. }, .. }, _) => {
(true, false, ctx.completion.config.snippet_cap)
diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs
index 42324b4..37d0fa1 100644
--- a/crates/ide-completion/src/render/variant.rs
+++ b/crates/ide-completion/src/render/variant.rs
@@ -26,14 +26,23 @@
return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
}
let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
+ let mut fmt_field = |fill, tab| {
+ let field_name = field.name(ctx.db);
+
+ if let Some(local) = ctx.locals.get(&field_name)
+ && local
+ .ty(ctx.db)
+ .could_unify_with_deeply(ctx.db, &field.ty(ctx.db).to_type(ctx.db))
+ {
+ f(&format_args!("{}{tab}", field_name.display(ctx.db, ctx.edition)))
+ } else {
+ f(&format_args!("{}: {fill}", field_name.display(ctx.db, ctx.edition)))
+ }
+ };
if snippet_cap.is_some() {
- f(&format_args!(
- "{}: ${{{}:()}}",
- field.name(ctx.db).display(ctx.db, ctx.edition),
- idx + 1
- ))
+ fmt_field(format_args!("${{{}:()}}", idx + 1), format_args!("${}", idx + 1))
} else {
- f(&format_args!("{}: ()", field.name(ctx.db).display(ctx.db, ctx.edition)))
+ fmt_field(format_args!("()"), format_args!(""))
}
});
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index ec9cd9f..83606d2 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -29,7 +29,7 @@
use hir::db::HirDatabase;
use hir::{PrefixKind, setup_tracing};
use ide_db::{
- FilePosition, RootDatabase, SnippetCap,
+ FilePosition, MiniCore, RootDatabase, SnippetCap,
imports::insert_use::{ImportGranularity, InsertUseConfig},
};
use itertools::Itertools;
@@ -90,6 +90,7 @@
exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
+ minicore: MiniCore::default(),
};
pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
@@ -245,11 +246,10 @@
let (db, position) = position(ra_fixture_before);
let completions: Vec<CompletionItem> =
hir::attach_db(&db, || crate::completions(&db, &config, position, None).unwrap());
- let (completion,) = completions
- .iter()
- .filter(|it| it.lookup() == what)
- .collect_tuple()
- .unwrap_or_else(|| panic!("can't find {what:?} completion in {completions:#?}"));
+ let Some((completion,)) = completions.iter().filter(|it| it.lookup() == what).collect_tuple()
+ else {
+ panic!("can't find {what:?} completion in {completions:#?}")
+ };
let mut actual = db.file_text(position.file_id).text(&db).to_string();
let mut combined_edit = completion.text_edit.clone();
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 1d2a9c7..2a62389 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -33,6 +33,7 @@
at diagnostic::do_not_recommend
at diagnostic::on_unimplemented
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -85,6 +86,7 @@
at deprecated
at derive(…)
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -158,6 +160,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -189,6 +192,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -212,6 +216,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -238,6 +243,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -264,6 +270,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -288,6 +295,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -313,6 +321,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -337,6 +346,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -368,6 +378,7 @@
at derive(…)
at derive_const macro derive_const
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -396,6 +407,7 @@
at deprecated
at derive(…)
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -422,6 +434,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -446,6 +459,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -476,6 +490,7 @@
at deprecated
at diagnostic::on_unimplemented
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -502,6 +517,7 @@
at deprecated
at diagnostic::do_not_recommend
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -522,6 +538,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -548,6 +565,7 @@
at deprecated
at do_not_recommend
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -566,6 +584,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -616,6 +635,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -637,6 +657,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -682,6 +703,7 @@
at deny(…)
at deprecated
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
@@ -724,6 +746,7 @@
at diagnostic::do_not_recommend
at diagnostic::on_unimplemented
at doc = "…"
+ at doc = include_str!("…")
at doc(alias = "…")
at doc(hidden)
at expect(…)
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 5363a68..4033aa5 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1869,6 +1869,298 @@
sn ppd
"#]],
);
+ check(
+ r#"
+fn foo() { [if foo {} $0]}
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { [if foo {} el$0]}
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { 2 + if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { -if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { &mut if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { return if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw else if
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { match () { () => if foo {} $0 } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { match () { () => if foo {} $0, } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { match () { () => if foo {} $0, _ => (), } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ // FIXME: support else completion after ast::RecordExprField
}
#[test]
@@ -2937,8 +3229,51 @@
}
#[test]
+fn ambiguous_float_literal_in_ambiguous_method_call() {
+ check(
+ r#"
+#![rustc_coherence_is_core]
+
+impl i32 {
+ pub fn int_method(self) {}
+}
+impl f64 {
+ pub fn float_method(self) {}
+}
+
+fn foo() -> (i32, i32) {
+ 1.$0
+ (2, 3)
+}
+ "#,
+ expect![[r#"
+ me int_method() fn(self)
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+}
+
+#[test]
fn let_in_condition() {
check_edit("let", r#"fn f() { if $0 {} }"#, r#"fn f() { if let $1 = $0 {} }"#);
+ check_edit("let", r#"fn f() { if $0x {} }"#, r#"fn f() { if let $1 = $0x {} }"#);
+ check_edit(
+ "let",
+ r#"fn f() { if $0foo.bar() {} }"#,
+ r#"fn f() { if let $1 = $0foo.bar() {} }"#,
+ );
}
#[test]
@@ -2947,6 +3282,293 @@
}
#[test]
+fn let_in_previous_line_of_ambiguous_expr() {
+ check_edit(
+ "let",
+ r#"
+ fn f() {
+ $0
+ (1, 2).foo();
+ }"#,
+ r#"
+ fn f() {
+ let $1 = $0;
+ (1, 2).foo();
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() {
+ $0
+ (1, 2)
+ }"#,
+ r#"
+ fn f() {
+ let $1 = $0;
+ (1, 2)
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> i32 {
+ $0
+ -2
+ }"#,
+ r#"
+ fn f() -> i32 {
+ let $1 = $0;
+ -2
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> [i32; 2] {
+ $0
+ [1, 2]
+ }"#,
+ r#"
+ fn f() -> [i32; 2] {
+ let $1 = $0;
+ [1, 2]
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> [u8; 2] {
+ $0
+ *b"01"
+ }"#,
+ r#"
+ fn f() -> [u8; 2] {
+ let $1 = $0;
+ *b"01"
+ }"#,
+ );
+
+ check(
+ r#"
+ fn foo() {
+ $0
+ *b"01"
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+
+ check(
+ r#"
+ fn foo() {
+ match $0 {}
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw const
+ kw crate::
+ kw false
+ kw for
+ kw if
+ kw if let
+ kw loop
+ kw match
+ kw return
+ kw self::
+ kw true
+ kw unsafe
+ kw while
+ kw while let
+ "#]],
+ );
+
+ check(
+ r#"
+ fn foo() {
+ $0 *b"01"
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw const
+ kw crate::
+ kw false
+ kw for
+ kw if
+ kw if let
+ kw loop
+ kw match
+ kw return
+ kw self::
+ kw true
+ kw unsafe
+ kw while
+ kw while let
+ "#]],
+ );
+}
+
+#[test]
+fn field_in_previous_line_of_ambiguous_expr() {
+ check(
+ r#"
+ struct Foo { field: i32 }
+ impl Foo {
+ fn method(&self) {}
+ }
+ fn foo() -> (i32, i32) {
+ let foo = Foo { field: 4 };
+ foo.$0
+ (2, 3)
+ }"#,
+ expect![[r#"
+ fd field i32
+ me method() fn(&self)
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+
+ check(
+ r#"
+ struct Foo { field: i32 }
+ impl Foo {
+ fn method(&self) {}
+ }
+ fn foo() -> (i32, i32) {
+ let foo = Foo { field: 4 };
+ foo.a$0
+ (2, 3)
+ }"#,
+ expect![[r#"
+ fd field i32
+ me method() fn(&self)
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+}
+
+#[test]
+fn fn_field_in_previous_line_of_ambiguous_expr() {
+ check(
+ r#"
+ struct Foo { field: fn() }
+ impl Foo {
+ fn method(&self) {}
+ }
+ fn foo() -> (i32, i32) {
+ let foo = Foo { field: || () };
+ foo.$0
+ (2, 3)
+ }"#,
+ expect![[r#"
+ fd field fn()
+ me method() fn(&self)
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+
+ check_edit(
+ "field",
+ r#"
+ struct Foo { field: fn() }
+ impl Foo {
+ fn method(&self) {}
+ }
+ fn foo() -> (i32, i32) {
+ let foo = Foo { field: || () };
+ foo.a$0
+ (2, 3)
+ }"#,
+ r#"
+ struct Foo { field: fn() }
+ impl Foo {
+ fn method(&self) {}
+ }
+ fn foo() -> (i32, i32) {
+ let foo = Foo { field: || () };
+ (foo.field)()
+ (2, 3)
+ }"#,
+ );
+}
+
+#[test]
fn private_inherent_and_public_trait() {
check(
r#"
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 2d3ebad..0cd4208 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -16,7 +16,8 @@
expect: Expect,
) {
let (db, position) = crate::tests::position(ra_fixture);
- let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
+ let (ctx, analysis) =
+ crate::context::CompletionContext::new(&db, position, &config, None).unwrap();
let mut acc = crate::completions::Completions::default();
hir::attach_db(ctx.db, || {
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index ed87b33..61a9da8 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -23,6 +23,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
@@ -45,6 +49,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs
index 65036f6..682b890 100644
--- a/crates/ide-completion/src/tests/predicate.rs
+++ b/crates/ide-completion/src/tests/predicate.rs
@@ -22,6 +22,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -95,6 +99,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -120,6 +128,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index c438ca7..59a0c14 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1492,6 +1492,10 @@
expect![[r#"
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -1506,6 +1510,10 @@
tp T
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -1531,6 +1539,10 @@
expect![[r#"
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 125e11e..3bbba18 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -25,6 +25,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
@@ -50,6 +54,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw pub
kw pub(crate)
kw pub(super)
@@ -76,6 +84,37 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
+ kw self::
+ "#]],
+ );
+}
+
+#[test]
+fn fn_return_type_after_reference() {
+ check_with_base_items(
+ r#"
+fn x<'lt, T, const C: usize>(_: &()) -> &$0
+"#,
+ expect![[r#"
+ en Enum Enum
+ ma makro!(…) macro_rules! makro
+ md module
+ st Record Record
+ st Tuple Tuple
+ st Unit Unit
+ tt Trait
+ tp T
+ un Union Union
+ bt u32 u32
+ kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -106,6 +145,10 @@
bt u32 u32
it ()
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
@@ -131,6 +174,10 @@
bt u32 u32
it Foo<i32>
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -157,6 +204,10 @@
bt u32 u32
it i32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -185,6 +236,10 @@
bt u32 u32
it u64
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -210,6 +265,10 @@
bt u32 u32
it u64
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -236,6 +295,10 @@
bt u32 u32
it i32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -270,6 +333,10 @@
bt u32 u32
it a::Foo<a::Foo<i32>>
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -299,6 +366,10 @@
bt u32 u32
it Foo<i32>
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -325,6 +396,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -392,6 +467,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -442,6 +521,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -487,6 +570,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -512,6 +599,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -555,6 +646,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -582,6 +677,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -625,6 +724,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -650,6 +753,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -666,6 +773,10 @@
ct CONST Unit
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -690,6 +801,10 @@
st Foo Foo
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
@@ -716,6 +831,10 @@
st S S
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
)
@@ -745,6 +864,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -765,6 +888,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -791,6 +918,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -808,6 +939,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -835,6 +970,10 @@
un Union Union
bt u32 u32
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -852,6 +991,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -870,6 +1013,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -889,6 +1036,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -907,6 +1058,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -923,6 +1078,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -941,6 +1100,10 @@
ct X usize
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -955,6 +1118,10 @@
ct CONST Unit
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -968,6 +1135,10 @@
ct CONST Unit
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
@@ -980,6 +1151,10 @@
lt 'a
ma makro!(…) macro_rules! makro
kw crate::
+ kw dyn
+ kw fn
+ kw for
+ kw impl
kw self::
"#]],
);
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index e065adb..b714816 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -30,6 +30,7 @@
triomphe.workspace = true
nohash-hasher.workspace = true
bitflags.workspace = true
+smallvec.workspace = true
# local deps
base-db.workspace = true
@@ -42,15 +43,15 @@
# ide should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
hir.workspace = true
+macros.workspace = true
+
+test-utils.workspace = true
+test-fixture.workspace = true
line-index.workspace = true
[dev-dependencies]
expect-test = "1.5.1"
-# local deps
-test-utils.workspace = true
-test-fixture.workspace = true
-
[lints]
workspace = true
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 44bccd8..7efa97b 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -2,6 +2,8 @@
//!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
+extern crate self as ide_db;
+
mod apply_change;
pub mod active_parameter;
@@ -14,6 +16,8 @@
pub mod label;
pub mod path_transform;
pub mod prime_caches;
+pub mod ra_fixture;
+pub mod range_mapper;
pub mod rename;
pub mod rust_doc;
pub mod search;
@@ -364,3 +368,25 @@
WeakWarning,
Allow,
}
+
+#[derive(Debug, Clone, Copy)]
+pub struct MiniCore<'a>(&'a str);
+
+impl<'a> MiniCore<'a> {
+ #[inline]
+ pub fn new(minicore: &'a str) -> Self {
+ Self(minicore)
+ }
+
+ #[inline]
+ pub const fn default() -> Self {
+ Self(test_utils::MiniCore::RAW_SOURCE)
+ }
+}
+
+impl<'a> Default for MiniCore<'a> {
+ #[inline]
+ fn default() -> Self {
+ Self::default()
+ }
+}
diff --git a/crates/ide-db/src/ra_fixture.rs b/crates/ide-db/src/ra_fixture.rs
new file mode 100644
index 0000000..1f056a8
--- /dev/null
+++ b/crates/ide-db/src/ra_fixture.rs
@@ -0,0 +1,532 @@
+//! Working with the fixtures in r-a tests, and providing IDE services for them.
+
+use std::hash::{BuildHasher, Hash};
+
+use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics};
+use smallvec::SmallVec;
+use span::{TextRange, TextSize};
+use syntax::{
+ AstToken, SmolStr,
+ ast::{self, IsString},
+};
+
+use crate::{
+ MiniCore, RootDatabase, SymbolKind, active_parameter::ActiveParameter,
+ documentation::Documentation, range_mapper::RangeMapper, search::ReferenceCategory,
+};
+
+pub use span::FileId;
+
+impl RootDatabase {
+ fn from_ra_fixture(
+ text: &str,
+ minicore: MiniCore<'_>,
+ ) -> Result<(RootDatabase, Vec<(FileId, usize)>, Vec<FileId>), ()> {
+ // We don't want a mistake in the fixture to crash r-a, so we wrap this in `catch_unwind()`.
+ std::panic::catch_unwind(|| {
+ let mut db = RootDatabase::default();
+ let fixture = test_fixture::ChangeFixture::parse_with_proc_macros(
+ &db,
+ text,
+ minicore.0,
+ Vec::new(),
+ );
+ db.apply_change(fixture.change);
+ let files = fixture
+ .files
+ .into_iter()
+ .zip(fixture.file_lines)
+ .map(|(file_id, range)| (file_id.file_id(&db), range))
+ .collect();
+ (db, files, fixture.sysroot_files)
+ })
+ .map_err(|error| {
+ tracing::error!(
+ "cannot crate the crate graph: {}\nCrate graph:\n{}\n",
+ if let Some(&s) = error.downcast_ref::<&'static str>() {
+ s
+ } else if let Some(s) = error.downcast_ref::<String>() {
+ s.as_str()
+ } else {
+ "Box<dyn Any>"
+ },
+ text,
+ );
+ })
+ }
+}
+
+pub struct RaFixtureAnalysis {
+ pub db: RootDatabase,
+ tmp_file_ids: Vec<(FileId, usize)>,
+ line_offsets: Vec<TextSize>,
+ virtual_file_id_to_line: Vec<usize>,
+ mapper: RangeMapper,
+ literal: ast::String,
+ // `minicore` etc..
+ sysroot_files: Vec<FileId>,
+ combined_len: TextSize,
+}
+
+impl RaFixtureAnalysis {
+ pub fn analyze_ra_fixture(
+ sema: &Semantics<'_, RootDatabase>,
+ literal: ast::String,
+ expanded: &ast::String,
+ minicore: MiniCore<'_>,
+ on_cursor: &mut dyn FnMut(TextRange),
+ ) -> Option<RaFixtureAnalysis> {
+ if !literal.is_raw() {
+ return None;
+ }
+
+ let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?;
+ let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
+ attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
+ path.segments()
+ .zip(["rust_analyzer", "rust_fixture"])
+ .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
+ })
+ });
+ if !has_rust_fixture_attr {
+ return None;
+ }
+ let value = literal.value().ok()?;
+
+ let mut mapper = RangeMapper::default();
+
+ // This is used for the `Injector`, to resolve precise location in the string literal,
+ // which will then be used to resolve precise location in the enclosing file.
+ let mut offset_with_indent = TextSize::new(0);
+ // This is used to resolve the location relative to the virtual file into a location
+ // relative to the indentation-trimmed file which will then (by the `Injector`) used
+ // to resolve to a location in the actual file.
+ // Besides indentation, we also skip `$0` cursors for this, since they are not included
+ // in the virtual files.
+ let mut offset_without_indent = TextSize::new(0);
+
+ let mut text = &*value;
+ if let Some(t) = text.strip_prefix('\n') {
+ offset_with_indent += TextSize::of("\n");
+ text = t;
+ }
+ // This stores the offsets of each line, **after we remove indentation**.
+ let mut line_offsets = Vec::new();
+ for mut line in text.split_inclusive('\n') {
+ line_offsets.push(offset_without_indent);
+
+ if line.starts_with("@@") {
+ // Introducing `//` into a fixture inside fixture causes all sorts of problems,
+ // so for testing purposes we escape it as `@@` and replace it here.
+ mapper.add("//", TextRange::at(offset_with_indent, TextSize::of("@@")));
+ line = &line["@@".len()..];
+ offset_with_indent += TextSize::of("@@");
+ offset_without_indent += TextSize::of("@@");
+ }
+
+ // Remove indentation to simplify the mapping with fixture (which de-indents).
+ // Removing indentation shouldn't affect highlighting.
+ let mut unindented_line = line.trim_start();
+ if unindented_line.is_empty() {
+ // The whole line was whitespaces, but we need the newline.
+ unindented_line = "\n";
+ }
+ offset_with_indent += TextSize::of(line) - TextSize::of(unindented_line);
+
+ let marker = "$0";
+ match unindented_line.find(marker) {
+ Some(marker_pos) => {
+ let (before_marker, after_marker) = unindented_line.split_at(marker_pos);
+ let after_marker = &after_marker[marker.len()..];
+
+ mapper.add(
+ before_marker,
+ TextRange::at(offset_with_indent, TextSize::of(before_marker)),
+ );
+ offset_with_indent += TextSize::of(before_marker);
+ offset_without_indent += TextSize::of(before_marker);
+
+ if let Some(marker_range) = literal
+ .map_range_up(TextRange::at(offset_with_indent, TextSize::of(marker)))
+ {
+ on_cursor(marker_range);
+ }
+ offset_with_indent += TextSize::of(marker);
+
+ mapper.add(
+ after_marker,
+ TextRange::at(offset_with_indent, TextSize::of(after_marker)),
+ );
+ offset_with_indent += TextSize::of(after_marker);
+ offset_without_indent += TextSize::of(after_marker);
+ }
+ None => {
+ mapper.add(
+ unindented_line,
+ TextRange::at(offset_with_indent, TextSize::of(unindented_line)),
+ );
+ offset_with_indent += TextSize::of(unindented_line);
+ offset_without_indent += TextSize::of(unindented_line);
+ }
+ }
+ }
+
+ let combined = mapper.take_text();
+ let combined_len = TextSize::of(&combined);
+ let (analysis, tmp_file_ids, sysroot_files) =
+ RootDatabase::from_ra_fixture(&combined, minicore).ok()?;
+
+ // We use a `Vec` because we know the `FileId`s will always be close.
+ let mut virtual_file_id_to_line = Vec::new();
+ for &(file_id, line) in &tmp_file_ids {
+ virtual_file_id_to_line.resize(file_id.index() as usize + 1, usize::MAX);
+ virtual_file_id_to_line[file_id.index() as usize] = line;
+ }
+
+ Some(RaFixtureAnalysis {
+ db: analysis,
+ tmp_file_ids,
+ line_offsets,
+ virtual_file_id_to_line,
+ mapper,
+ literal,
+ sysroot_files,
+ combined_len,
+ })
+ }
+
+ pub fn files(&self) -> impl Iterator<Item = FileId> {
+ self.tmp_file_ids.iter().map(|(file, _)| *file)
+ }
+
+ /// This returns `None` for minicore or other sysroot files.
+ fn virtual_file_id_to_line(&self, file_id: FileId) -> Option<usize> {
+ if self.is_sysroot_file(file_id) {
+ None
+ } else {
+ Some(self.virtual_file_id_to_line[file_id.index() as usize])
+ }
+ }
+
+ pub fn map_offset_down(&self, offset: TextSize) -> Option<(FileId, TextSize)> {
+ let inside_literal_range = self.literal.map_offset_down(offset)?;
+ let combined_offset = self.mapper.map_offset_down(inside_literal_range)?;
+ // There is usually a small number of files, so a linear search is smaller and faster.
+ let (_, &(file_id, file_line)) =
+ self.tmp_file_ids.iter().enumerate().find(|&(idx, &(_, file_line))| {
+ let file_start = self.line_offsets[file_line];
+ let file_end = self
+ .tmp_file_ids
+ .get(idx + 1)
+ .map(|&(_, next_file_line)| self.line_offsets[next_file_line])
+ .unwrap_or_else(|| self.combined_len);
+ TextRange::new(file_start, file_end).contains(combined_offset)
+ })?;
+ let file_line_offset = self.line_offsets[file_line];
+ let file_offset = combined_offset - file_line_offset;
+ Some((file_id, file_offset))
+ }
+
+ pub fn map_range_down(&self, range: TextRange) -> Option<(FileId, TextRange)> {
+ let (start_file_id, start_offset) = self.map_offset_down(range.start())?;
+ let (end_file_id, end_offset) = self.map_offset_down(range.end())?;
+ if start_file_id != end_file_id {
+ None
+ } else {
+ Some((start_file_id, TextRange::new(start_offset, end_offset)))
+ }
+ }
+
+ pub fn map_range_up(
+ &self,
+ virtual_file: FileId,
+ range: TextRange,
+ ) -> impl Iterator<Item = TextRange> {
+ // This could be `None` if the file is empty.
+ self.virtual_file_id_to_line(virtual_file)
+ .and_then(|line| self.line_offsets.get(line))
+ .into_iter()
+ .flat_map(move |&tmp_file_offset| {
+ // Resolve the offset relative to the virtual file to an offset relative to the combined indentation-trimmed file
+ let range = range + tmp_file_offset;
+ // Then resolve that to an offset relative to the real file.
+ self.mapper.map_range_up(range)
+ })
+ // And finally resolve the offset relative to the literal to relative to the file.
+ .filter_map(|range| self.literal.map_range_up(range))
+ }
+
+ pub fn map_offset_up(&self, virtual_file: FileId, offset: TextSize) -> Option<TextSize> {
+ self.map_range_up(virtual_file, TextRange::empty(offset)).next().map(|range| range.start())
+ }
+
+ pub fn is_sysroot_file(&self, file_id: FileId) -> bool {
+ self.sysroot_files.contains(&file_id)
+ }
+}
+
+pub trait UpmapFromRaFixture: Sized {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()>;
+}
+
+trait IsEmpty {
+ fn is_empty(&self) -> bool;
+}
+
+impl<T> IsEmpty for Vec<T> {
+ fn is_empty(&self) -> bool {
+ self.is_empty()
+ }
+}
+
+impl<T, const N: usize> IsEmpty for SmallVec<[T; N]> {
+ fn is_empty(&self) -> bool {
+ self.is_empty()
+ }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K, V, S> IsEmpty for std::collections::HashMap<K, V, S> {
+ fn is_empty(&self) -> bool {
+ self.is_empty()
+ }
+}
+
+fn upmap_collection<T, Collection>(
+ collection: Collection,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+) -> Result<Collection, ()>
+where
+ T: UpmapFromRaFixture,
+ Collection: IntoIterator<Item = T> + FromIterator<T> + IsEmpty,
+{
+ if collection.is_empty() {
+ // The collection was already empty, don't mark it as failing just because of that.
+ return Ok(collection);
+ }
+ let result = collection
+ .into_iter()
+ .filter_map(|item| item.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok())
+ .collect::<Collection>();
+ if result.is_empty() {
+ // The collection was emptied by the upmapping - all items errored, therefore mark it as erroring as well.
+ Err(())
+ } else {
+ Ok(result)
+ }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Option<T> {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ Ok(match self {
+ Some(it) => Some(it.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?),
+ None => None,
+ })
+ }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Vec<T> {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ upmap_collection(self, analysis, virtual_file_id, real_file_id)
+ }
+}
+
+impl<T: UpmapFromRaFixture, const N: usize> UpmapFromRaFixture for SmallVec<[T; N]> {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ upmap_collection(self, analysis, virtual_file_id, real_file_id)
+ }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K: UpmapFromRaFixture + Hash + Eq, V: UpmapFromRaFixture, S: BuildHasher + Default>
+ UpmapFromRaFixture for std::collections::HashMap<K, V, S>
+{
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ upmap_collection(self, analysis, virtual_file_id, real_file_id)
+ }
+}
+
+// A map of `FileId`s is treated as associating the ranges in the values with the keys.
+#[allow(clippy::disallowed_types)]
+impl<V: UpmapFromRaFixture, S: BuildHasher + Default> UpmapFromRaFixture
+ for std::collections::HashMap<FileId, V, S>
+{
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ _virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ if self.is_empty() {
+ return Ok(self);
+ }
+ let result = self
+ .into_iter()
+ .filter_map(|(virtual_file_id, value)| {
+ Some((
+ real_file_id,
+ value.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok()?,
+ ))
+ })
+ .collect::<std::collections::HashMap<_, _, _>>();
+ if result.is_empty() { Err(()) } else { Ok(result) }
+ }
+}
+
+macro_rules! impl_tuple {
+ () => {}; // Base case.
+ ( $first:ident, $( $rest:ident, )* ) => {
+ impl<
+ $first: UpmapFromRaFixture,
+ $( $rest: UpmapFromRaFixture, )*
+ > UpmapFromRaFixture for ( $first, $( $rest, )* ) {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ #[allow(non_snake_case)]
+ let ( $first, $($rest,)* ) = self;
+ Ok((
+ $first.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+ $( $rest.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, )*
+ ))
+ }
+ }
+
+ impl_tuple!( $($rest,)* );
+ };
+}
+impl_tuple!(A, B, C, D, E,);
+
+impl UpmapFromRaFixture for TextSize {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ _real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ analysis.map_offset_up(virtual_file_id, self).ok_or(())
+ }
+}
+
+impl UpmapFromRaFixture for TextRange {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ virtual_file_id: FileId,
+ _real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ analysis.map_range_up(virtual_file_id, self).next().ok_or(())
+ }
+}
+
+// Deliberately do not implement that, as it's easy to get things misbehave and be treated with the wrong FileId:
+//
+// impl UpmapFromRaFixture for FileId {
+// fn upmap_from_ra_fixture(
+// self,
+// _analysis: &RaFixtureAnalysis,
+// _virtual_file_id: FileId,
+// real_file_id: FileId,
+// ) -> Result<Self, ()> {
+// Ok(real_file_id)
+// }
+// }
+
+impl UpmapFromRaFixture for FilePositionWrapper<FileId> {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ _virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ Ok(FilePositionWrapper {
+ file_id: real_file_id,
+ offset: self.offset.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+ })
+ }
+}
+
+impl UpmapFromRaFixture for FileRangeWrapper<FileId> {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &RaFixtureAnalysis,
+ _virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ Ok(FileRangeWrapper {
+ file_id: real_file_id,
+ range: self.range.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+ })
+ }
+}
+
+#[macro_export]
+macro_rules! impl_empty_upmap_from_ra_fixture {
+ ( $( $ty:ty ),* $(,)? ) => {
+ $(
+ impl $crate::ra_fixture::UpmapFromRaFixture for $ty {
+ fn upmap_from_ra_fixture(
+ self,
+ _analysis: &$crate::ra_fixture::RaFixtureAnalysis,
+ _virtual_file_id: $crate::ra_fixture::FileId,
+ _real_file_id: $crate::ra_fixture::FileId,
+ ) -> Result<Self, ()> {
+ Ok(self)
+ }
+ }
+ )*
+ };
+}
+
+impl_empty_upmap_from_ra_fixture!(
+ bool,
+ i8,
+ i16,
+ i32,
+ i64,
+ i128,
+ u8,
+ u16,
+ u32,
+ u64,
+ u128,
+ f32,
+ f64,
+ &str,
+ String,
+ SmolStr,
+ Documentation,
+ SymbolKind,
+ CfgExpr,
+ ReferenceCategory,
+);
diff --git a/crates/ide-db/src/range_mapper.rs b/crates/ide-db/src/range_mapper.rs
new file mode 100644
index 0000000..ef84888
--- /dev/null
+++ b/crates/ide-db/src/range_mapper.rs
@@ -0,0 +1,65 @@
+//! Maps between ranges in documents.
+
+use std::cmp::Ordering;
+
+use stdx::equal_range_by;
+use syntax::{TextRange, TextSize};
+
+#[derive(Default)]
+pub struct RangeMapper {
+ buf: String,
+ ranges: Vec<(TextRange, Option<TextRange>)>,
+}
+
+impl RangeMapper {
+ pub fn add(&mut self, text: &str, source_range: TextRange) {
+ let len = TextSize::of(text);
+ assert_eq!(len, source_range.len());
+ self.add_impl(text, Some(source_range.start()));
+ }
+
+ pub fn add_unmapped(&mut self, text: &str) {
+ self.add_impl(text, None);
+ }
+
+ fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
+ let len = TextSize::of(text);
+ let target_range = TextRange::at(TextSize::of(&self.buf), len);
+ self.ranges.push((target_range, source.map(|it| TextRange::at(it, len))));
+ self.buf.push_str(text);
+ }
+
+ pub fn take_text(&mut self) -> String {
+ std::mem::take(&mut self.buf)
+ }
+
+ pub fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
+ equal_range_by(&self.ranges, |&(r, _)| {
+ if range.is_empty() && r.contains(range.start()) {
+ Ordering::Equal
+ } else {
+ TextRange::ordering(r, range)
+ }
+ })
+ .filter_map(move |i| {
+ let (target_range, source_range) = self.ranges[i];
+ let intersection = target_range.intersect(range).unwrap();
+ let source_range = source_range?;
+ Some(intersection - target_range.start() + source_range.start())
+ })
+ }
+
+ pub fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+ // Using a binary search here is a bit complicated because of the `None` entries.
+ // But the number of lines in fixtures is usually low.
+ let (target_range, source_range) =
+ self.ranges.iter().find_map(|&(target_range, source_range)| {
+ let source_range = source_range?;
+ if !source_range.contains(offset) {
+ return None;
+ }
+ Some((target_range, source_range))
+ })?;
+ Some(offset - source_range.start() + target_range.start())
+ }
+}
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs
index 16c0d8d..57072bb 100644
--- a/crates/ide-db/src/source_change.rs
+++ b/crates/ide-db/src/source_change.rs
@@ -10,6 +10,7 @@
use crate::{SnippetCap, assists::Command, syntax_helpers::tree_diff::diff};
use base_db::AnchoredPathBuf;
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use nohash_hasher::IntMap;
use rustc_hash::FxHashMap;
use span::FileId;
@@ -20,7 +21,7 @@
};
/// An annotation ID associated with an indel, to describe changes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, UpmapFromRaFixture)]
pub struct ChangeAnnotationId(u32);
impl fmt::Display for ChangeAnnotationId {
diff --git a/crates/ide-db/src/text_edit.rs b/crates/ide-db/src/text_edit.rs
index 6e9bd7b..d2a7371 100644
--- a/crates/ide-db/src/text_edit.rs
+++ b/crates/ide-db/src/text_edit.rs
@@ -5,6 +5,7 @@
//! rust-analyzer.
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
pub use span::{TextRange, TextSize};
use std::cmp::max;
@@ -13,14 +14,14 @@
/// `InsertDelete` -- a single "atomic" change to text
///
/// Must not overlap with other `InDel`s
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, UpmapFromRaFixture)]
pub struct Indel {
pub insert: String,
/// Refers to offsets in the original text
pub delete: TextRange,
}
-#[derive(Default, Debug, Clone)]
+#[derive(Default, Debug, Clone, UpmapFromRaFixture)]
pub struct TextEdit {
/// Invariant: disjoint and sorted by `delete`.
indels: Vec<Indel>,
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 25c1e63..4ed71f0 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -488,4 +488,27 @@
"#,
);
}
+
+ #[test]
+ fn regression_17233() {
+ check_diagnostics(
+ r#"
+pub trait A {
+ type X: B;
+}
+pub trait B: A {
+ fn confused_name(self, _: i32);
+}
+
+pub struct Foo;
+impl Foo {
+ pub fn confused_name(&self) {}
+}
+
+pub fn repro<T: A>() {
+ Foo.confused_name();
+}
+"#,
+ );
+ }
}
diff --git a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index e31367f..c86ecd2 100644
--- a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -155,4 +155,56 @@
"#,
);
}
+
+ #[test]
+ fn uninhabited_variants() {
+ check_diagnostics(
+ r#"
+//- minicore: result
+enum Infallible {}
+
+trait Foo {
+ type Bar;
+}
+
+struct Wrapper<T> {
+ error: T,
+}
+
+struct FooWrapper<T: Foo> {
+ error: T::Bar,
+}
+
+fn foo<T: Foo<Bar = Infallible>>(result: Result<T, T::Bar>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+
+fn bar<T: Foo<Bar = Infallible>>(result: Result<T, (T::Bar,)>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+
+fn baz<T: Foo<Bar = Infallible>>(result: Result<T, Wrapper<T::Bar>>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+
+fn qux<T: Foo<Bar = Infallible>>(result: Result<T, FooWrapper<T>>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+
+fn quux<T: Foo<Bar = Infallible>>(result: Result<T, [T::Bar; 1]>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+
+fn corge<T: Foo<Bar = Infallible>>(result: Result<T, (i32, T::Bar)>) -> T {
+ let Ok(ok) = result;
+ ok
+}
+"#,
+ );
+ }
}
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 37af05e..3dc155e 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -311,7 +311,7 @@
}
fn check(minicore: MiniCore) {
- let source = minicore.source_code();
+ let source = minicore.source_code(MiniCore::RAW_SOURCE);
let mut config = DiagnosticsConfig::test_sample();
// This should be ignored since we conditionally remove code which creates single item use with braces
config.disabled.insert("unused_braces".to_owned());
@@ -321,7 +321,7 @@
}
// Checks that there is no diagnostic in minicore for each flag.
- for flag in MiniCore::available_flags() {
+ for flag in MiniCore::available_flags(MiniCore::RAW_SOURCE) {
if flag == "clone" {
// Clone without copy has `moved-out-of-ref`, so ignoring.
// FIXME: Maybe we should merge copy and clone in a single flag?
@@ -332,5 +332,5 @@
}
// And one time for all flags, to check codes which are behind multiple flags + prevent name collisions
eprintln!("Checking all minicore flags");
- check(MiniCore::from_flags(MiniCore::available_flags()))
+ check(MiniCore::from_flags(MiniCore::available_flags(MiniCore::RAW_SOURCE)))
}
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 06d2776..08ffd39 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -42,6 +42,7 @@
# ide should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
hir.workspace = true
+macros.workspace = true
[target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies]
toolchain.workspace = true
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index dec1889..36c4404 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -1,6 +1,6 @@
use hir::{HasSource, InFile, InRealFile, Semantics};
use ide_db::{
- FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+ FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition,
helpers::visit_file_defs,
};
use itertools::Itertools;
@@ -11,7 +11,7 @@
annotations::fn_references::find_all_methods,
goto_implementation::goto_implementation,
navigation_target,
- references::find_all_refs,
+ references::{FindAllRefsConfig, find_all_refs},
runnables::{Runnable, runnables},
};
@@ -36,7 +36,7 @@
HasReferences { pos: FilePosition, data: Option<Vec<FileRange>> },
}
-pub struct AnnotationConfig {
+pub struct AnnotationConfig<'a> {
pub binary_target: bool,
pub annotate_runnables: bool,
pub annotate_impls: bool,
@@ -44,6 +44,7 @@
pub annotate_method_references: bool,
pub annotate_enum_variant_references: bool,
pub location: AnnotationLocation,
+ pub minicore: MiniCore<'a>,
}
pub enum AnnotationLocation {
@@ -53,7 +54,7 @@
pub(crate) fn annotations(
db: &RootDatabase,
- config: &AnnotationConfig,
+ config: &AnnotationConfig<'_>,
file_id: FileId,
) -> Vec<Annotation> {
let mut annotations = FxIndexSet::default();
@@ -196,13 +197,22 @@
.collect()
}
-pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
+pub(crate) fn resolve_annotation(
+ db: &RootDatabase,
+ config: &AnnotationConfig<'_>,
+ mut annotation: Annotation,
+) -> Annotation {
match annotation.kind {
AnnotationKind::HasImpls { pos, ref mut data } => {
*data = goto_implementation(db, pos).map(|range| range.info);
}
AnnotationKind::HasReferences { pos, ref mut data } => {
- *data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
+ *data = find_all_refs(
+ &Semantics::new(db),
+ pos,
+ &FindAllRefsConfig { search_scope: None, minicore: config.minicore },
+ )
+ .map(|result| {
result
.into_iter()
.flat_map(|res| res.references)
@@ -228,12 +238,13 @@
#[cfg(test)]
mod tests {
use expect_test::{Expect, expect};
+ use ide_db::MiniCore;
use crate::{Annotation, AnnotationConfig, fixture};
use super::AnnotationLocation;
- const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig {
+ const DEFAULT_CONFIG: AnnotationConfig<'_> = AnnotationConfig {
binary_target: true,
annotate_runnables: true,
annotate_impls: true,
@@ -241,12 +252,13 @@
annotate_method_references: true,
annotate_enum_variant_references: true,
location: AnnotationLocation::AboveName,
+ minicore: MiniCore::default(),
};
fn check_with_config(
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
- config: &AnnotationConfig,
+ config: &AnnotationConfig<'_>,
) {
let (analysis, file_id) = fixture::file(ra_fixture);
@@ -254,7 +266,7 @@
.annotations(config, file_id)
.unwrap()
.into_iter()
- .map(|annotation| analysis.resolve_annotation(annotation).unwrap())
+ .map(|annotation| analysis.resolve_annotation(&DEFAULT_CONFIG, annotation).unwrap())
.collect();
expect.assert_debug_eq(&annotations);
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index f42cead..aded911 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -4,14 +4,16 @@
use hir::Semantics;
use ide_db::{
- FileRange, FxIndexMap, RootDatabase,
+ FileRange, FxIndexMap, MiniCore, RootDatabase,
defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token,
search::FileReference,
};
use syntax::{AstNode, SyntaxKind::IDENT, ast};
-use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav, goto_definition};
+use crate::{
+ FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo, TryToNav, goto_definition,
+};
#[derive(Debug, Clone)]
pub struct CallItem {
@@ -19,22 +21,28 @@
pub ranges: Vec<FileRange>,
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct CallHierarchyConfig {
+#[derive(Debug, Clone, Copy)]
+pub struct CallHierarchyConfig<'a> {
/// Whether to exclude tests from the call hierarchy
pub exclude_tests: bool,
+ pub minicore: MiniCore<'a>,
}
pub(crate) fn call_hierarchy(
db: &RootDatabase,
position: FilePosition,
+ config: &CallHierarchyConfig<'_>,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
- goto_definition::goto_definition(db, position)
+ goto_definition::goto_definition(
+ db,
+ position,
+ &GotoDefinitionConfig { minicore: config.minicore },
+ )
}
pub(crate) fn incoming_calls(
db: &RootDatabase,
- CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+ config: &CallHierarchyConfig<'_>,
FilePosition { file_id, offset }: FilePosition,
) -> Option<Vec<CallItem>> {
let sema = &Semantics::new(db);
@@ -71,7 +79,7 @@
});
if let Some((def, nav)) = def_nav {
- if exclude_tests && def.is_test(db) {
+ if config.exclude_tests && def.is_test(db) {
continue;
}
@@ -89,7 +97,7 @@
pub(crate) fn outgoing_calls(
db: &RootDatabase,
- CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+ config: &CallHierarchyConfig<'_>,
FilePosition { file_id, offset }: FilePosition,
) -> Option<Vec<CallItem>> {
let sema = Semantics::new(db);
@@ -119,7 +127,7 @@
let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
match callable.kind() {
hir::CallableKind::Function(it) => {
- if exclude_tests && it.is_test(db) {
+ if config.exclude_tests && it.is_test(db) {
return None;
}
it.try_to_nav(&sema)
@@ -132,7 +140,7 @@
}
ast::CallableExpr::MethodCall(expr) => {
let function = sema.resolve_method_call(&expr)?;
- if exclude_tests && function.is_test(db) {
+ if config.exclude_tests && function.is_test(db) {
return None;
}
function
@@ -166,7 +174,7 @@
#[cfg(test)]
mod tests {
use expect_test::{Expect, expect};
- use ide_db::FilePosition;
+ use ide_db::{FilePosition, MiniCore};
use itertools::Itertools;
use crate::fixture;
@@ -189,21 +197,20 @@
)
}
+ let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() };
let (analysis, pos) = fixture::position(ra_fixture);
- let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
+ let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info;
assert_eq!(navs.len(), 1);
let nav = navs.pop().unwrap();
expected_nav.assert_eq(&nav.debug_render());
- let config = crate::CallHierarchyConfig { exclude_tests };
-
let item_pos =
FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
- let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap();
+ let incoming_calls = analysis.incoming_calls(&config, item_pos).unwrap().unwrap();
expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
- let outgoing_calls = analysis.outgoing_calls(config, item_pos).unwrap().unwrap();
+ let outgoing_calls = analysis.outgoing_calls(&config, item_pos).unwrap().unwrap();
expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
}
diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs
index 686dbe2..375ce94 100644
--- a/crates/ide/src/goto_declaration.rs
+++ b/crates/ide/src/goto_declaration.rs
@@ -6,8 +6,8 @@
use syntax::{AstNode, SyntaxKind::*, T, ast, match_ast};
use crate::{
- FilePosition, NavigationTarget, RangeInfo, goto_definition::goto_definition,
- navigation_target::TryToNav,
+ FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo,
+ goto_definition::goto_definition, navigation_target::TryToNav,
};
// Feature: Go to Declaration
@@ -21,6 +21,7 @@
pub(crate) fn goto_declaration(
db: &RootDatabase,
position @ FilePosition { file_id, offset }: FilePosition,
+ config: &GotoDefinitionConfig<'_>,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
let sema = Semantics::new(db);
let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -69,20 +70,27 @@
.flatten()
.collect();
- if info.is_empty() { goto_definition(db, position) } else { Some(RangeInfo::new(range, info)) }
+ if info.is_empty() {
+ goto_definition(db, position, config)
+ } else {
+ Some(RangeInfo::new(range, info))
+ }
}
#[cfg(test)]
mod tests {
- use ide_db::FileRange;
+ use ide_db::{FileRange, MiniCore};
use itertools::Itertools;
- use crate::fixture;
+ use crate::{GotoDefinitionConfig, fixture};
+
+ const TEST_CONFIG: GotoDefinitionConfig<'_> =
+ GotoDefinitionConfig { minicore: MiniCore::default() };
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (analysis, position, expected) = fixture::annotations(ra_fixture);
let navs = analysis
- .goto_declaration(position)
+ .goto_declaration(position, &TEST_CONFIG)
.unwrap()
.expect("no declaration or definition found")
.info;
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 2dcb13d..0ee9795 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,5 +1,6 @@
use std::{iter, mem::discriminant};
+use crate::Analysis;
use crate::{
FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
doc_links::token_as_doc_comment,
@@ -8,6 +9,7 @@
use hir::{
AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
};
+use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
use ide_db::{
RootDatabase, SymbolKind,
base_db::{AnchoredPath, SourceDatabase},
@@ -25,6 +27,11 @@
match_ast,
};
+#[derive(Debug)]
+pub struct GotoDefinitionConfig<'a> {
+ pub minicore: MiniCore<'a>,
+}
+
// Feature: Go to Definition
//
// Navigates to the definition of an identifier.
@@ -39,6 +46,7 @@
pub(crate) fn goto_definition(
db: &RootDatabase,
FilePosition { file_id, offset }: FilePosition,
+ config: &GotoDefinitionConfig<'_>,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
let sema = &Semantics::new(db);
let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -83,52 +91,64 @@
return Some(RangeInfo::new(original_token.text_range(), navs));
}
- let navs = sema
- .descend_into_macros_no_opaque(original_token.clone(), false)
- .into_iter()
- .filter_map(|token| {
- if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
- return Some(navs);
- }
+ let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
+ let mut navs = Vec::new();
+ for token in tokens {
+ if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
+ navs.extend(n);
+ continue;
+ }
- let parent = token.value.parent()?;
+ if let Some(token) = ast::String::cast(token.value.clone())
+ && let Some(original_token) = ast::String::cast(original_token.clone())
+ && let Some((analysis, fixture_analysis)) =
+ Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
+ && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
+ {
+ return hir::attach_db_allow_change(&analysis.db, || {
+ goto_definition(
+ &analysis.db,
+ FilePosition { file_id: virtual_file_id, offset: file_offset },
+ config,
+ )
+ })
+ .and_then(|navs| {
+ navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()
+ });
+ }
- let token_file_id = token.file_id;
- if let Some(token) = ast::String::cast(token.value.clone())
- && let Some(x) =
- try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
- {
- return Some(vec![x]);
- }
+ let parent = token.value.parent()?;
- if ast::TokenTree::can_cast(parent.kind())
- && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
- {
- return Some(vec![x]);
- }
+ let token_file_id = token.file_id;
+ if let Some(token) = ast::String::cast(token.value.clone())
+ && let Some(x) =
+ try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
+ {
+ navs.push(x);
+ continue;
+ }
- Some(
- IdentClass::classify_node(sema, &parent)?
- .definitions()
+ if ast::TokenTree::can_cast(parent.kind())
+ && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
+ {
+ navs.push(x);
+ continue;
+ }
+
+ let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };
+ navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {
+ if let Definition::ExternCrateDecl(crate_def) = def {
+ return crate_def
+ .resolved_crate(db)
+ .map(|it| it.root_module().to_nav(sema.db))
.into_iter()
- .flat_map(|(def, _)| {
- if let Definition::ExternCrateDecl(crate_def) = def {
- return crate_def
- .resolved_crate(db)
- .map(|it| it.root_module().to_nav(sema.db))
- .into_iter()
- .flatten()
- .collect();
- }
- try_filter_trait_item_definition(sema, &def)
- .unwrap_or_else(|| def_to_nav(sema, def))
- })
- .collect(),
- )
- })
- .flatten()
- .unique()
- .collect::<Vec<NavigationTarget>>();
+ .flatten()
+ .collect();
+ }
+ try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))
+ }));
+ }
+ let navs = navs.into_iter().unique().collect();
Some(RangeInfo::new(original_token.text_range(), navs))
}
@@ -584,15 +604,22 @@
#[cfg(test)]
mod tests {
- use crate::fixture;
- use ide_db::FileRange;
+ use crate::{GotoDefinitionConfig, fixture};
+ use ide_db::{FileRange, MiniCore};
use itertools::Itertools;
use syntax::SmolStr;
+ const TEST_CONFIG: GotoDefinitionConfig<'_> =
+ GotoDefinitionConfig { minicore: MiniCore::default() };
+
#[track_caller]
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (analysis, position, expected) = fixture::annotations(ra_fixture);
- let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+ let navs = analysis
+ .goto_definition(position, &TEST_CONFIG)
+ .unwrap()
+ .expect("no definition found")
+ .info;
let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
let navs = navs
@@ -611,14 +638,22 @@
fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (analysis, position) = fixture::position(ra_fixture);
- let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+ let navs = analysis
+ .goto_definition(position, &TEST_CONFIG)
+ .unwrap()
+ .expect("no definition found")
+ .info;
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
}
fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (analysis, position, _) = fixture::annotations(ra_fixture);
- let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+ let navs = analysis
+ .goto_definition(position, &TEST_CONFIG)
+ .unwrap()
+ .expect("no definition found")
+ .info;
assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
let Some(target) = navs.into_iter().next() else {
panic!("expected single navigation target but encountered none");
@@ -3961,4 +3996,87 @@
"#,
);
}
+
+ #[test]
+ fn ra_fixture() {
+ check(
+ r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+ fixture(r#"
+fn foo() {}
+// ^^^
+fn bar() {
+ f$0oo();
+}
+ "#)
+}
+ "##,
+ );
+ }
+
+ #[test]
+ fn regression_20038() {
+ check(
+ r#"
+//- minicore: clone, fn
+struct Map<Fut, F>(Fut, F);
+
+struct InspectFn<F>(F);
+
+trait FnOnce1<A> {
+ type Output;
+}
+
+trait Future1 {
+ type Output;
+}
+
+trait FusedFuture1: Future1 {
+ fn is_terminated(&self) -> bool;
+ //^^^^^^^^^^^^^
+}
+
+impl<T, A, R> FnOnce1<A> for T
+where
+ T: FnOnce(A) -> R,
+{
+ type Output = R;
+}
+
+impl<F, A> FnOnce1<A> for InspectFn<F>
+where
+ F: for<'a> FnOnce1<&'a A, Output = ()>,
+{
+ type Output = A;
+}
+
+impl<Fut, F, T> Future1 for Map<Fut, F>
+where
+ Fut: Future1,
+ F: FnOnce1<Fut::Output, Output = T>,
+{
+ type Output = T;
+}
+
+impl<Fut, F, T> FusedFuture1 for Map<Fut, F>
+where
+ Fut: Future1,
+ F: FnOnce1<Fut::Output, Output = T>,
+{
+ fn is_terminated(&self) -> bool {
+ false
+ }
+}
+
+fn overflows<Fut, F>(inner: &Map<Fut, InspectFn<F>>)
+where
+ Map<Fut, InspectFn<F>>: FusedFuture1
+{
+ let _x = inner.is_terminated$0();
+}
+"#,
+ )
+ }
}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c4fb6d1..e1d18b0 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -11,29 +11,32 @@
db::DefDatabase,
};
use ide_db::{
- FileRange, FxIndexSet, Ranker, RootDatabase,
+ FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
defs::{Definition, IdentClass, NameRefClass, OperatorClass},
famous_defs::FamousDefs,
helpers::pick_best_token,
+ ra_fixture::UpmapFromRaFixture,
};
use itertools::{Itertools, multizip};
-use span::Edition;
+use macros::UpmapFromRaFixture;
+use span::{Edition, TextRange};
use syntax::{
- AstNode,
+ AstNode, AstToken,
SyntaxKind::{self, *},
SyntaxNode, T, ast,
};
use crate::{
- FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
+ Analysis, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
doc_links::token_as_doc_comment,
markdown_remove::remove_markdown,
markup::Markup,
navigation_target::UpmappingResult,
runnables::{runnable_fn, runnable_mod},
};
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct HoverConfig {
+
+#[derive(Clone, Debug)]
+pub struct HoverConfig<'a> {
pub links_in_hover: bool,
pub memory_layout: Option<MemoryLayoutHoverConfig>,
pub documentation: bool,
@@ -44,6 +47,7 @@
pub max_enum_variants_count: Option<usize>,
pub max_subst_ty_len: SubstTyLen,
pub show_drop_glue: bool,
+ pub minicore: MiniCore<'a>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -75,7 +79,7 @@
PlainText,
}
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
pub enum HoverAction {
Runnable(Runnable),
Implementation(FilePosition),
@@ -108,14 +112,14 @@
}
}
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, UpmapFromRaFixture)]
pub struct HoverGotoTypeData {
pub mod_path: String,
pub nav: NavigationTarget,
}
/// Contains the results when hovering over an item
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, UpmapFromRaFixture)]
pub struct HoverResult {
pub markup: Markup,
pub actions: Vec<HoverAction>,
@@ -130,7 +134,7 @@
pub(crate) fn hover(
db: &RootDatabase,
frange @ FileRange { file_id, range }: FileRange,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
) -> Option<RangeInfo<HoverResult>> {
let sema = &hir::Semantics::new(db);
let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -161,7 +165,7 @@
sema: &Semantics<'_, RootDatabase>,
FilePosition { file_id, offset }: FilePosition,
file: SyntaxNode,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
edition: Edition,
display_target: DisplayTarget,
) -> Option<RangeInfo<HoverResult>> {
@@ -219,6 +223,21 @@
return Some(RangeInfo::new(range, res));
}
+ if let Some(literal) = ast::String::cast(original_token.clone())
+ && let Some((analysis, fixture_analysis)) =
+ Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+ {
+ let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?;
+ return analysis
+ .hover(
+ config,
+ FileRange { file_id: virtual_file_id, range: TextRange::empty(virtual_offset) },
+ )
+ .ok()??
+ .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+ .ok();
+ }
+
// prefer descending the same token kind in attribute expansions, in normal macros text
// equivalency is more important
let mut descended = sema.descend_into_macros(original_token.clone());
@@ -383,9 +402,9 @@
fn hover_ranged(
sema: &Semantics<'_, RootDatabase>,
- FileRange { range, .. }: FileRange,
+ FileRange { file_id, range }: FileRange,
file: SyntaxNode,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
edition: Edition,
display_target: DisplayTarget,
) -> Option<RangeInfo<HoverResult>> {
@@ -404,6 +423,20 @@
{
render::deref_expr(sema, config, prefix_expr, edition, display_target)
}
+ Either::Left(ast::Expr::Literal(literal)) => {
+ if let Some(literal) = ast::String::cast(literal.token())
+ && let Some((analysis, fixture_analysis)) =
+ Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+ {
+ let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?;
+ return analysis
+ .hover(config, FileRange { file_id: virtual_file_id, range: virtual_range })
+ .ok()??
+ .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+ .ok();
+ }
+ None
+ }
_ => None,
};
let res =
@@ -426,7 +459,7 @@
scope_node: &SyntaxNode,
macro_arm: Option<u32>,
render_extras: bool,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
edition: Edition,
display_target: DisplayTarget,
) -> HoverResult {
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index f29ccc9..a1eff3a 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -35,7 +35,7 @@
pub(super) fn type_info_of(
sema: &Semantics<'_, RootDatabase>,
- _config: &HoverConfig,
+ _config: &HoverConfig<'_>,
expr_or_pat: &Either<ast::Expr, ast::Pat>,
edition: Edition,
display_target: DisplayTarget,
@@ -49,7 +49,7 @@
pub(super) fn closure_expr(
sema: &Semantics<'_, RootDatabase>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
c: ast::ClosureExpr,
edition: Edition,
display_target: DisplayTarget,
@@ -60,7 +60,7 @@
pub(super) fn try_expr(
sema: &Semantics<'_, RootDatabase>,
- _config: &HoverConfig,
+ _config: &HoverConfig<'_>,
try_expr: &ast::TryExpr,
edition: Edition,
display_target: DisplayTarget,
@@ -155,7 +155,7 @@
pub(super) fn deref_expr(
sema: &Semantics<'_, RootDatabase>,
- _config: &HoverConfig,
+ _config: &HoverConfig<'_>,
deref_expr: &ast::PrefixExpr,
edition: Edition,
display_target: DisplayTarget,
@@ -219,7 +219,7 @@
pub(super) fn underscore(
sema: &Semantics<'_, RootDatabase>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
token: &SyntaxToken,
edition: Edition,
display_target: DisplayTarget,
@@ -263,7 +263,7 @@
pub(super) fn keyword(
sema: &Semantics<'_, RootDatabase>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
token: &SyntaxToken,
edition: Edition,
display_target: DisplayTarget,
@@ -290,7 +290,7 @@
/// i.e. `let S {a, ..} = S {a: 1, b: 2}`
pub(super) fn struct_rest_pat(
sema: &Semantics<'_, RootDatabase>,
- _config: &HoverConfig,
+ _config: &HoverConfig<'_>,
pattern: &ast::RecordPat,
edition: Edition,
display_target: DisplayTarget,
@@ -371,7 +371,7 @@
def: Definition,
markup: &Markup,
markup_range_map: Option<DocsRangeMap>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
) -> Markup {
let markup = markup.as_str();
let markup = if config.links_in_hover {
@@ -481,7 +481,7 @@
macro_arm: Option<u32>,
render_extras: bool,
subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
edition: Edition,
display_target: DisplayTarget,
) -> (Markup, Option<DocsRangeMap>) {
@@ -979,7 +979,7 @@
fn type_info(
sema: &Semantics<'_, RootDatabase>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
ty: TypeInfo<'_>,
edition: Edition,
display_target: DisplayTarget,
@@ -1038,7 +1038,7 @@
fn closure_ty(
sema: &Semantics<'_, RootDatabase>,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
TypeInfo { original, adjusted }: &TypeInfo<'_>,
edition: Edition,
display_target: DisplayTarget,
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df18006..91fb4d0 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -1,5 +1,5 @@
use expect_test::{Expect, expect};
-use ide_db::{FileRange, base_db::SourceDatabase};
+use ide_db::{FileRange, MiniCore, base_db::SourceDatabase};
use syntax::TextRange;
use crate::{
@@ -8,7 +8,7 @@
use hir::setup_tracing;
-const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
+const HOVER_BASE_CONFIG: HoverConfig<'_> = HoverConfig {
links_in_hover: false,
memory_layout: Some(MemoryLayoutHoverConfig {
size: Some(MemoryLayoutHoverRenderKind::Both),
@@ -25,6 +25,7 @@
max_enum_variants_count: Some(5),
max_subst_ty_len: super::SubstTyLen::Unlimited,
show_drop_glue: true,
+ minicore: MiniCore::default(),
};
fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index f7b09b4..21550d5 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,9 +8,12 @@
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
};
-use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
+use ide_db::{
+ FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+};
use ide_db::{FxHashSet, text_edit::TextEdit};
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use smallvec::{SmallVec, smallvec};
use stdx::never;
use syntax::{
@@ -37,6 +40,7 @@
mod implied_dyn_trait;
mod lifetime;
mod param_name;
+mod ra_fixture;
mod range_exclusive;
// Feature: Inlay Hints
@@ -80,7 +84,7 @@
db: &RootDatabase,
file_id: FileId,
range_limit: Option<TextRange>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
) -> Vec<InlayHint> {
let _p = tracing::info_span!("inlay_hints").entered();
let sema = Semantics::new(db);
@@ -132,7 +136,7 @@
file_id: FileId,
resolve_range: TextRange,
hash: u64,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
hasher: impl Fn(&InlayHint) -> u64,
) -> Option<InlayHint> {
let _p = tracing::info_span!("inlay_hints_resolve").entered();
@@ -208,7 +212,7 @@
hints: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
file_id: EditionedFileId,
display_target: DisplayTarget,
node: SyntaxNode,
@@ -239,6 +243,7 @@
closure_ret::hints(hints, famous_defs, config, display_target, it)
},
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
+ ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it),
_ => Some(()),
}
},
@@ -294,8 +299,8 @@
};
}
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct InlayHintsConfig {
+#[derive(Clone, Debug)]
+pub struct InlayHintsConfig<'a> {
pub render_colons: bool,
pub type_hints: bool,
pub sized_bound: bool,
@@ -321,9 +326,10 @@
pub max_length: Option<usize>,
pub closing_brace_hints_min_lines: Option<usize>,
pub fields_to_resolve: InlayFieldsToResolve,
+ pub minicore: MiniCore<'a>,
}
-impl InlayHintsConfig {
+impl InlayHintsConfig<'_> {
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
if self.fields_to_resolve.resolve_text_edits {
LazyProperty::Lazy
@@ -466,7 +472,7 @@
After,
}
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
pub struct InlayHint {
/// The text range this inlay hint applies to.
pub range: TextRange,
@@ -485,9 +491,10 @@
}
/// A type signaling that a value is either computed, or is available for computation.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default, UpmapFromRaFixture)]
pub enum LazyProperty<T> {
Computed(T),
+ #[default]
Lazy,
}
@@ -537,7 +544,7 @@
Markdown(String),
}
-#[derive(Default, Hash)]
+#[derive(Default, Hash, UpmapFromRaFixture)]
pub struct InlayHintLabel {
pub parts: SmallVec<[InlayHintLabelPart; 1]>,
}
@@ -623,6 +630,7 @@
}
}
+#[derive(UpmapFromRaFixture)]
pub struct InlayHintLabelPart {
pub text: String,
/// Source location represented by this label part. The client will use this to fetch the part's
@@ -724,7 +732,7 @@
fn label_of_ty(
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
ty: &hir::Type<'_>,
display_target: DisplayTarget,
) -> Option<InlayHintLabel> {
@@ -734,7 +742,7 @@
mut max_length: Option<usize>,
ty: &hir::Type<'_>,
label_builder: &mut InlayHintLabelBuilder<'_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
) -> Result<(), HirDisplayError> {
hir::attach_db(sema.db, || {
@@ -829,7 +837,7 @@
fn ty_to_text_edit(
sema: &Semantics<'_, RootDatabase>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
node_for_hint: &SyntaxNode,
ty: &hir::Type<'_>,
offset_to_insert_ty: TextSize,
@@ -860,6 +868,7 @@
use expect_test::Expect;
use hir::ClosureStyle;
+ use ide_db::MiniCore;
use itertools::Itertools;
use test_utils::extract_annotations;
@@ -869,7 +878,7 @@
use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
- pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
+ pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
discriminant_hints: DiscriminantHints::Never,
render_colons: false,
type_hints: false,
@@ -899,8 +908,9 @@
fields_to_resolve: InlayFieldsToResolve::empty(),
implicit_drop_hints: false,
range_exclusive_hints: false,
+ minicore: MiniCore::default(),
};
- pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
+ pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
type_hints: true,
parameter_hints: true,
chaining_hints: true,
@@ -917,7 +927,7 @@
#[track_caller]
pub(super) fn check_with_config(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) {
let (analysis, file_id) = fixture::file(ra_fixture);
@@ -936,7 +946,7 @@
#[track_caller]
pub(super) fn check_expect(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
@@ -951,7 +961,7 @@
/// expect test.
#[track_caller]
pub(super) fn check_edit(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
@@ -974,7 +984,7 @@
#[track_caller]
pub(super) fn check_no_edit(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) {
let (analysis, file_id) = fixture::file(ra_fixture);
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 7231a31..ebb0d57 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -23,7 +23,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
expr: &ast::Expr,
) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 121b16b..de207c7 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -20,7 +20,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
pat: &ast::IdentPat,
) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index 169ab92..e8d305a 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -15,7 +15,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
pat: &ast::Pat,
) -> Option<()> {
if !config.binding_mode_hints {
diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs
index 4abd67b..c9fbdf3 100644
--- a/crates/ide/src/inlay_hints/bounds.rs
+++ b/crates/ide/src/inlay_hints/bounds.rs
@@ -13,7 +13,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
params: ast::GenericParamList,
) -> Option<()> {
if !config.sized_bound {
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index a8bb652..cf3149c 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -13,7 +13,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
expr: &ast::Expr,
) -> Option<()> {
@@ -93,7 +93,7 @@
#[track_caller]
pub(super) fn check_expect_clear_loc(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs
index 9d246ed..ab3ce5b 100644
--- a/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/crates/ide/src/inlay_hints/closing_brace.rs
@@ -19,7 +19,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<'_, RootDatabase>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
InRealFile { file_id, value: node }: InRealFile<SyntaxNode>,
) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs
index 3186a56..f8d4ddc 100644
--- a/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/crates/ide/src/inlay_hints/closure_captures.rs
@@ -13,7 +13,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
closure: ast::ClosureExpr,
) -> Option<()> {
if !config.closure_capture_hints {
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index fef1cb8..7765dc4 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -13,7 +13,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
closure: ast::ClosureExpr,
) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index a2a7028..5b92671 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -17,7 +17,7 @@
pub(super) fn enum_hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
enum_: ast::Enum,
) -> Option<()> {
if let DiscriminantHints::Never = config.discriminant_hints {
@@ -41,7 +41,7 @@
fn variant_hints(
acc: &mut Vec<InlayHint>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
sema: &Semantics<'_, RootDatabase>,
enum_: &ast::Enum,
variant: &ast::Variant,
diff --git a/crates/ide/src/inlay_hints/extern_block.rs b/crates/ide/src/inlay_hints/extern_block.rs
index 491018a..8dd6c4d 100644
--- a/crates/ide/src/inlay_hints/extern_block.rs
+++ b/crates/ide/src/inlay_hints/extern_block.rs
@@ -7,7 +7,7 @@
pub(super) fn extern_block_hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
extern_block: ast::ExternBlock,
) -> Option<()> {
if extern_block.unsafe_token().is_some() {
@@ -33,7 +33,7 @@
pub(super) fn fn_hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
fn_: &ast::Fn,
extern_block: &ast::ExternBlock,
) -> Option<()> {
@@ -51,7 +51,7 @@
pub(super) fn static_hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
static_: &ast::Static,
extern_block: &ast::ExternBlock,
) -> Option<()> {
@@ -67,7 +67,7 @@
}
fn item_hint(
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
extern_block: &ast::ExternBlock,
token: SyntaxToken,
) -> InlayHint {
diff --git a/crates/ide/src/inlay_hints/generic_param.rs b/crates/ide/src/inlay_hints/generic_param.rs
index 1fddb6f..27d14f7 100644
--- a/crates/ide/src/inlay_hints/generic_param.rs
+++ b/crates/ide/src/inlay_hints/generic_param.rs
@@ -16,7 +16,7 @@
pub(crate) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, krate): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
node: AnyHasGenericArgs,
) -> Option<()> {
let GenericParameterHints { type_hints, lifetime_hints, const_hints } =
diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs
index 1e272fe..951a672 100644
--- a/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -23,7 +23,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: hir::DisplayTarget,
node: &ast::Fn,
) -> Option<()> {
@@ -147,7 +147,7 @@
inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
};
- const ONLY_DROP_CONFIG: InlayHintsConfig =
+ const ONLY_DROP_CONFIG: InlayHintsConfig<'_> =
InlayHintsConfig { implicit_drop_hints: true, ..DISABLED_CONFIG };
#[test]
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index bddce90..0492991 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -15,7 +15,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
statik_or_const: Either<ast::Static, ast::Const>,
) -> Option<()> {
if config.lifetime_elision_hints != LifetimeElisionHints::Always {
diff --git a/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
index 0da1785..562eb1e 100644
--- a/crates/ide/src/inlay_hints/implied_dyn_trait.rs
+++ b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -11,7 +11,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
path: Either<ast::PathType, ast::DynTraitType>,
) -> Option<()> {
let parent = path.syntax().parent()?;
diff --git a/crates/ide/src/inlay_hints/lifetime.rs b/crates/ide/src/inlay_hints/lifetime.rs
index a89c53e..4982b60 100644
--- a/crates/ide/src/inlay_hints/lifetime.rs
+++ b/crates/ide/src/inlay_hints/lifetime.rs
@@ -21,7 +21,7 @@
acc: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
fd: &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
func: ast::Fn,
) -> Option<()> {
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -70,7 +70,7 @@
acc: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
fd: &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
func: ast::FnPtrType,
) -> Option<()> {
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -135,7 +135,7 @@
acc: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
fd: &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
func: &ast::PathType,
) -> Option<()> {
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -196,7 +196,7 @@
acc: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
FamousDefs(_, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
generic_param_list: Option<ast::GenericParamList>,
ret_type: Option<ast::RetType>,
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 7547077..4122c16 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -18,7 +18,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, krate): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
file_id: EditionedFileId,
expr: ast::Expr,
) -> Option<()> {
@@ -124,12 +124,12 @@
// hide when:
// - the parameter name is a suffix of the function's name
// - the argument is a qualified constructing or call expression where the qualifier is an ADT
- // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
- // of argument with _ splitting it off
+ // - exact argument<->parameter match(ignoring leading and trailing underscore) or
+ // parameter is a prefix/suffix of argument with _ splitting it off
// - param starts with `ra_fixture`
// - param is a well known name in a unary function
- let param_name = param_name.trim_start_matches('_');
+ let param_name = param_name.trim_matches('_');
if param_name.is_empty() {
return true;
}
@@ -540,6 +540,8 @@
fn foo(param: u32) {}
fn bar(param_eter: u32) {}
fn baz(a_d_e: u32) {}
+fn far(loop_: u32) {}
+fn faz(r#loop: u32) {}
enum CompletionKind {
Keyword,
@@ -590,6 +592,9 @@
let param_eter2 = 0;
bar(param_eter2);
//^^^^^^^^^^^ param_eter
+ let loop_level = 0;
+ far(loop_level);
+ faz(loop_level);
non_ident_pat((0, 0));
diff --git a/crates/ide/src/inlay_hints/ra_fixture.rs b/crates/ide/src/inlay_hints/ra_fixture.rs
new file mode 100644
index 0000000..bee1841
--- /dev/null
+++ b/crates/ide/src/inlay_hints/ra_fixture.rs
@@ -0,0 +1,32 @@
+//! Injected inlay hints for `#[rust_analyzer::rust_fixture]`.
+
+use hir::{EditionedFileId, Semantics};
+use ide_db::{RootDatabase, impl_empty_upmap_from_ra_fixture, ra_fixture::UpmapFromRaFixture};
+use syntax::{AstToken, ast};
+
+use crate::{Analysis, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip};
+
+pub(super) fn hints(
+ acc: &mut Vec<InlayHint>,
+ sema: &Semantics<'_, RootDatabase>,
+ file_id: EditionedFileId,
+ config: &InlayHintsConfig<'_>,
+ literal: ast::Literal,
+) -> Option<()> {
+ let file_id = file_id.file_id(sema.db);
+ let literal = ast::String::cast(literal.token())?;
+ let (analysis, fixture_analysis) =
+ Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?;
+ for virtual_file_id in fixture_analysis.files() {
+ acc.extend(
+ analysis
+ .inlay_hints(config, virtual_file_id, None)
+ .ok()?
+ .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+ .ok()?,
+ );
+ }
+ Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(InlayHintPosition, InlayKind, InlayTooltip);
diff --git a/crates/ide/src/inlay_hints/range_exclusive.rs b/crates/ide/src/inlay_hints/range_exclusive.rs
index 47bd6d7..a446908 100644
--- a/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -11,7 +11,7 @@
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
range: impl ast::RangeItem,
) -> Option<()> {
(config.range_exclusive_hints && range.end().is_some())
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f7d21c9..8572528 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@
use cfg::CfgOptions;
use fetch_crates::CrateInfo;
-use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, db::HirDatabase, sym};
+use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
use ide_db::{
FxHashMap, FxIndexSet, LineIndexDatabase,
base_db::{
@@ -71,7 +71,9 @@
},
prime_caches, symbol_index,
};
-use syntax::SourceFile;
+use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis};
+use macros::UpmapFromRaFixture;
+use syntax::{SourceFile, ast};
use triomphe::Arc;
use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
@@ -83,6 +85,7 @@
expand_macro::ExpandedMacro,
file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
folding_ranges::{Fold, FoldKind},
+ goto_definition::GotoDefinitionConfig,
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{
HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
@@ -102,7 +105,7 @@
},
move_item::Direction,
navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
- references::ReferenceSearchResult,
+ references::{FindAllRefsConfig, ReferenceSearchResult},
rename::RenameError,
runnables::{Runnable, RunnableKind, TestId, UpdateTest},
signature_help::SignatureHelp,
@@ -144,7 +147,7 @@
pub type Cancellable<T> = Result<T, Cancelled>;
/// Info associated with a text range.
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
pub struct RangeInfo<T> {
pub range: TextRange,
pub info: T,
@@ -274,6 +277,28 @@
(host.analysis(), file_id)
}
+ pub(crate) fn from_ra_fixture(
+ sema: &Semantics<'_, RootDatabase>,
+ literal: ast::String,
+ expanded: &ast::String,
+ minicore: MiniCore<'_>,
+ ) -> Option<(Analysis, RaFixtureAnalysis)> {
+ Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {})
+ }
+
+ /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position.
+ pub(crate) fn from_ra_fixture_with_on_cursor(
+ sema: &Semantics<'_, RootDatabase>,
+ literal: ast::String,
+ expanded: &ast::String,
+ minicore: MiniCore<'_>,
+ on_cursor: &mut dyn FnMut(TextRange),
+ ) -> Option<(Analysis, RaFixtureAnalysis)> {
+ let analysis =
+ RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?;
+ Some((Analysis { db: analysis.db.clone() }, analysis))
+ }
+
/// Debug info about the current state of the analysis.
pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
self.with_db(|db| status::status(db, file_id))
@@ -446,7 +471,7 @@
/// Returns a list of the places in the file where type hints can be displayed.
pub fn inlay_hints(
&self,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
file_id: FileId,
range: Option<TextRange>,
) -> Cancellable<Vec<InlayHint>> {
@@ -454,7 +479,7 @@
}
pub fn inlay_hints_resolve(
&self,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
file_id: FileId,
resolve_range: TextRange,
hash: u64,
@@ -495,16 +520,18 @@
pub fn goto_definition(
&self,
position: FilePosition,
+ config: &GotoDefinitionConfig<'_>,
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
- self.with_db(|db| goto_definition::goto_definition(db, position))
+ self.with_db(|db| goto_definition::goto_definition(db, position, config))
}
/// Returns the declaration from the symbol at `position`.
pub fn goto_declaration(
&self,
position: FilePosition,
+ config: &GotoDefinitionConfig<'_>,
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
- self.with_db(|db| goto_declaration::goto_declaration(db, position))
+ self.with_db(|db| goto_declaration::goto_declaration(db, position, config))
}
/// Returns the impls from the symbol at `position`.
@@ -526,19 +553,16 @@
pub fn find_all_refs(
&self,
position: FilePosition,
- search_scope: Option<SearchScope>,
+ config: &FindAllRefsConfig<'_>,
) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
- let search_scope = AssertUnwindSafe(search_scope);
- self.with_db(|db| {
- let _ = &search_scope;
- references::find_all_refs(&Semantics::new(db), position, search_scope.0)
- })
+ let config = AssertUnwindSafe(config);
+ self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, &config))
}
/// Returns a short text describing element at position.
pub fn hover(
&self,
- config: &HoverConfig,
+ config: &HoverConfig<'_>,
range: FileRange,
) -> Cancellable<Option<RangeInfo<HoverResult>>> {
self.with_db(|db| hover::hover(db, range, config))
@@ -576,14 +600,15 @@
pub fn call_hierarchy(
&self,
position: FilePosition,
+ config: &CallHierarchyConfig<'_>,
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
- self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
+ self.with_db(|db| call_hierarchy::call_hierarchy(db, position, config))
}
/// Computes incoming calls for the given file position.
pub fn incoming_calls(
&self,
- config: CallHierarchyConfig,
+ config: &CallHierarchyConfig<'_>,
position: FilePosition,
) -> Cancellable<Option<Vec<CallItem>>> {
self.with_db(|db| call_hierarchy::incoming_calls(db, config, position))
@@ -592,7 +617,7 @@
/// Computes outgoing calls for the given file position.
pub fn outgoing_calls(
&self,
- config: CallHierarchyConfig,
+ config: &CallHierarchyConfig<'_>,
position: FilePosition,
) -> Cancellable<Option<Vec<CallItem>>> {
self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position))
@@ -675,28 +700,22 @@
/// Computes syntax highlighting for the given file
pub fn highlight(
&self,
- highlight_config: HighlightConfig,
+ highlight_config: HighlightConfig<'_>,
file_id: FileId,
) -> Cancellable<Vec<HlRange>> {
- // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
- // highlighting instead sets up the attach hook where neceesary for the trait solver
- Cancelled::catch(|| {
- syntax_highlighting::highlight(&self.db, highlight_config, file_id, None)
- })
+ self.with_db(|db| syntax_highlighting::highlight(db, &highlight_config, file_id, None))
}
/// Computes syntax highlighting for the given file range.
pub fn highlight_range(
&self,
- highlight_config: HighlightConfig,
+ highlight_config: HighlightConfig<'_>,
frange: FileRange,
) -> Cancellable<Vec<HlRange>> {
- // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
- // highlighting instead sets up the attach hook where neceesary for the trait solver
- Cancelled::catch(|| {
+ self.with_db(|db| {
syntax_highlighting::highlight(
- &self.db,
- highlight_config,
+ db,
+ &highlight_config,
frange.file_id,
Some(frange.range),
)
@@ -706,22 +725,18 @@
/// Computes syntax highlighting for the given file.
pub fn highlight_as_html_with_config(
&self,
- config: HighlightConfig,
+ config: HighlightConfig<'_>,
file_id: FileId,
rainbow: bool,
) -> Cancellable<String> {
- // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
- // highlighting instead sets up the attach hook where neceesary for the trait solver
- Cancelled::catch(|| {
- syntax_highlighting::highlight_as_html_with_config(&self.db, config, file_id, rainbow)
+ self.with_db(|db| {
+ syntax_highlighting::highlight_as_html_with_config(db, &config, file_id, rainbow)
})
}
/// Computes syntax highlighting for the given file.
pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
- // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
- // highlighting instead sets up the attach hook where neceesary for the trait solver
- Cancelled::catch(|| syntax_highlighting::highlight_as_html(&self.db, file_id, rainbow))
+ self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
}
/// Computes completions at the given position.
@@ -853,14 +868,18 @@
pub fn annotations(
&self,
- config: &AnnotationConfig,
+ config: &AnnotationConfig<'_>,
file_id: FileId,
) -> Cancellable<Vec<Annotation>> {
self.with_db(|db| annotations::annotations(db, config, file_id))
}
- pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
- self.with_db(|db| annotations::resolve_annotation(db, annotation))
+ pub fn resolve_annotation(
+ &self,
+ config: &AnnotationConfig<'_>,
+ annotation: Annotation,
+ ) -> Cancellable<Annotation> {
+ self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
}
pub fn move_item(
@@ -899,12 +918,8 @@
where
F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
{
- hir::attach_db(&self.db, || {
- // the trait solver code may invoke `as_view<HirDatabase>` outside of queries,
- // so technically we might run into a panic in salsa if the downcaster has not yet been registered.
- HirDatabase::zalsa_register_downcaster(&self.db);
- Cancelled::catch(|| f(&self.db))
- })
+ // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database.
+ hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
}
}
diff --git a/crates/ide/src/markup.rs b/crates/ide/src/markup.rs
index 750d125..3eb9986 100644
--- a/crates/ide/src/markup.rs
+++ b/crates/ide/src/markup.rs
@@ -5,6 +5,8 @@
//! what is used by LSP, so let's keep it simple.
use std::fmt;
+use ide_db::impl_empty_upmap_from_ra_fixture;
+
#[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
pub struct Markup {
text: String,
@@ -39,3 +41,5 @@
format!("```text\n{contents}\n```").into()
}
}
+
+impl_empty_upmap_from_ra_fixture!(Markup);
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index f1aa03c..4aa9eb9 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -384,7 +384,7 @@
})
}
-fn display<T: HirDisplay>(db: &RootDatabase, module: hir::Module, it: T) -> String {
+fn display<'db, T: HirDisplay<'db>>(db: &'db RootDatabase, module: hir::Module, it: T) -> String {
match it.display_source_code(db, module.into(), true) {
Ok(result) => result,
// Fallback on display variant that always succeeds
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index db12983..b222ff3 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -14,6 +14,7 @@
defs::{Definition, find_std_module},
documentation::{Documentation, HasDocs},
famous_defs::FamousDefs,
+ ra_fixture::UpmapFromRaFixture,
};
use span::Edition;
use stdx::never;
@@ -78,6 +79,44 @@
}
}
+impl UpmapFromRaFixture for NavigationTarget {
+ fn upmap_from_ra_fixture(
+ self,
+ analysis: &ide_db::ra_fixture::RaFixtureAnalysis,
+ _virtual_file_id: FileId,
+ real_file_id: FileId,
+ ) -> Result<Self, ()> {
+ let virtual_file_id = self.file_id;
+ Ok(NavigationTarget {
+ file_id: real_file_id,
+ full_range: self.full_range.upmap_from_ra_fixture(
+ analysis,
+ virtual_file_id,
+ real_file_id,
+ )?,
+ focus_range: self.focus_range.upmap_from_ra_fixture(
+ analysis,
+ virtual_file_id,
+ real_file_id,
+ )?,
+ name: self.name.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+ kind: self.kind.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+ container_name: self.container_name.upmap_from_ra_fixture(
+ analysis,
+ virtual_file_id,
+ real_file_id,
+ )?,
+ description: self.description.upmap_from_ra_fixture(
+ analysis,
+ virtual_file_id,
+ real_file_id,
+ )?,
+ docs: self.docs.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+ alias: self.alias.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+ })
+ }
+}
+
pub(crate) trait ToNav {
fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget>;
}
@@ -382,7 +421,7 @@
impl<D> TryToNav for D
where
- D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay + HasCrate,
+ D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate,
D::Ast: ast::HasName,
{
fn try_to_nav(
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 0189939..a53a192 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -19,14 +19,17 @@
use hir::{PathResolution, Semantics};
use ide_db::{
- FileId, RootDatabase,
+ FileId, MiniCore, RootDatabase,
defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token,
+ ra_fixture::UpmapFromRaFixture,
search::{ReferenceCategory, SearchScope, UsageSearchResult},
};
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use nohash_hasher::IntMap;
use span::Edition;
+use syntax::AstToken;
use syntax::{
AstNode,
SyntaxKind::*,
@@ -35,10 +38,12 @@
match_ast,
};
-use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
+use crate::{
+ Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related,
+};
/// Result of a reference search operation.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
pub struct ReferenceSearchResult {
/// Information about the declaration site of the searched item.
/// For ADTs (structs/enums), this points to the type definition.
@@ -54,7 +59,7 @@
}
/// Information about the declaration site of a searched item.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
pub struct Declaration {
/// Navigation information to jump to the declaration
pub nav: NavigationTarget,
@@ -82,6 +87,12 @@
//
// 
+#[derive(Debug)]
+pub struct FindAllRefsConfig<'a> {
+ pub search_scope: Option<SearchScope>,
+ pub minicore: MiniCore<'a>,
+}
+
/// Find all references to the item at the given position.
///
/// # Arguments
@@ -110,14 +121,14 @@
pub(crate) fn find_all_refs(
sema: &Semantics<'_, RootDatabase>,
position: FilePosition,
- search_scope: Option<SearchScope>,
+ config: &FindAllRefsConfig<'_>,
) -> Option<Vec<ReferenceSearchResult>> {
let _p = tracing::info_span!("find_all_refs").entered();
let syntax = sema.parse_guess_edition(position.file_id).syntax().clone();
let make_searcher = |literal_search: bool| {
move |def: Definition| {
let mut usages =
- def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
+ def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all();
if literal_search {
retain_adt_literal_usages(&mut usages, def, sema);
}
@@ -165,6 +176,20 @@
return Some(vec![res]);
}
+ if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
+ && let Some(token) = ast::String::cast(token.clone())
+ && let Some((analysis, fixture_analysis)) =
+ Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
+ && let Some((virtual_file_id, file_offset)) =
+ fixture_analysis.map_offset_down(position.offset)
+ {
+ return analysis
+ .find_all_refs(FilePosition { file_id: virtual_file_id, offset: file_offset }, config)
+ .ok()??
+ .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, position.file_id)
+ .ok();
+ }
+
match name_for_constructor_search(&syntax, position) {
Some(name) => {
let def = match NameClass::classify(sema, &name)? {
@@ -433,10 +458,10 @@
mod tests {
use expect_test::{Expect, expect};
use hir::EditionedFileId;
- use ide_db::{FileId, RootDatabase};
+ use ide_db::{FileId, MiniCore, RootDatabase};
use stdx::format_to;
- use crate::{SearchScope, fixture};
+ use crate::{SearchScope, fixture, references::FindAllRefsConfig};
#[test]
fn exclude_tests() {
@@ -1513,8 +1538,11 @@
expect: Expect,
) {
let (analysis, pos) = fixture::position(ra_fixture);
- let refs =
- analysis.find_all_refs(pos, search_scope.map(|it| it(&analysis.db))).unwrap().unwrap();
+ let config = FindAllRefsConfig {
+ search_scope: search_scope.map(|it| it(&analysis.db)),
+ minicore: MiniCore::default(),
+ };
+ let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
let mut actual = String::new();
for mut refs in refs {
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index cc1bbfb..494701d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -8,6 +8,7 @@
sym,
};
use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
+use ide_db::impl_empty_upmap_from_ra_fixture;
use ide_db::{
FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
base_db::RootQueryDb,
@@ -17,6 +18,7 @@
search::{FileReferenceNode, SearchScope},
};
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use smallvec::SmallVec;
use span::{Edition, TextSize};
use stdx::format_to;
@@ -28,7 +30,7 @@
use crate::{FileId, NavigationTarget, ToNav, TryToNav, references};
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
pub struct Runnable {
pub use_name_in_title: bool,
pub nav: NavigationTarget,
@@ -37,6 +39,8 @@
pub update_test: UpdateTest,
}
+impl_empty_upmap_from_ra_fixture!(RunnableKind, UpdateTest);
+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum TestId {
Name(SmolStr),
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 453d6f5..e261928 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -4,7 +4,7 @@
use arrayvec::ArrayVec;
use hir::{Crate, Module, Semantics, db::HirDatabase};
use ide_db::{
- FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+ FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase,
base_db::{RootQueryDb, SourceDatabase, VfsPath},
defs::{Definition, IdentClass},
documentation::Documentation,
@@ -184,6 +184,7 @@
closing_brace_hints_min_lines: Some(25),
fields_to_resolve: InlayFieldsToResolve::empty(),
range_exclusive_hints: false,
+ minicore: MiniCore::default(),
},
file_id,
None,
@@ -215,6 +216,7 @@
max_enum_variants_count: Some(5),
max_subst_ty_len: SubstTyLen::Unlimited,
show_drop_glue: true,
+ minicore: MiniCore::default(),
};
let tokens = tokens.filter(|token| {
matches!(
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 0da9ee0..66895cb 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -1,7 +1,6 @@
pub(crate) mod tags;
mod highlights;
-mod injector;
mod escape;
mod format;
@@ -16,7 +15,7 @@
use either::Either;
use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics};
-use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind};
use syntax::{
AstNode, AstToken, NodeOrToken,
SyntaxKind::*,
@@ -44,8 +43,8 @@
pub binding_hash: Option<u64>,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct HighlightConfig {
+#[derive(Copy, Clone, Debug)]
+pub struct HighlightConfig<'a> {
/// Whether to highlight strings
pub strings: bool,
/// Whether to highlight comments
@@ -64,6 +63,7 @@
pub macro_bang: bool,
/// Whether to highlight unresolved things be their syntax
pub syntactic_name_ref_highlighting: bool,
+ pub minicore: MiniCore<'a>,
}
// Feature: Semantic Syntax Highlighting
@@ -191,7 +191,7 @@
// 
pub(crate) fn highlight(
db: &RootDatabase,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
file_id: FileId,
range_to_highlight: Option<TextRange>,
) -> Vec<HlRange> {
@@ -226,7 +226,7 @@
fn traverse(
hl: &mut Highlights,
sema: &Semantics<'_, RootDatabase>,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
InRealFile { file_id, value: root }: InRealFile<&SyntaxNode>,
krate: Option<hir::Crate>,
range_to_highlight: TextRange,
@@ -426,12 +426,9 @@
let edition = descended_element.file_id.edition(sema.db);
let (unsafe_ops, bindings_shadow_count) = match current_body {
Some(current_body) => {
- let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| {
- (
- hir::attach_db(sema.db, || sema.get_unsafe_ops(current_body)),
- Default::default(),
- )
- });
+ let (ops, bindings) = per_body_cache
+ .entry(current_body)
+ .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default()));
(&*ops, Some(bindings))
}
None => (&empty, None),
@@ -494,7 +491,7 @@
fn string_injections(
hl: &mut Highlights,
sema: &Semantics<'_, RootDatabase>,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
file_id: EditionedFileId,
krate: Option<hir::Crate>,
token: SyntaxToken,
@@ -591,7 +588,7 @@
})
}
-fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool {
+fn filter_by_config(highlight: &mut Highlight, config: &HighlightConfig<'_>) -> bool {
match &mut highlight.tag {
HlTag::StringLiteral if !config.strings => return false,
HlTag::Comment if !config.comments => return false,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index d73575f..829d127 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -137,7 +137,7 @@
}
(T![!], MACRO_RULES) => HlPunct::MacroBang.into(),
(T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
- (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
+ (T![!], PREFIX_EXPR) => HlOperator::Negation.into(),
(T![*], PTR_TYPE) => HlTag::Keyword.into(),
(T![*], PREFIX_EXPR) => {
let h = HlTag::Operator(HlOperator::Other).into();
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 358ac9b..75e46b8 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -1,6 +1,7 @@
//! Renders a bit of code as HTML.
use hir::{EditionedFileId, Semantics};
+use ide_db::MiniCore;
use oorandom::Rand32;
use stdx::format_to;
use syntax::AstNode;
@@ -12,7 +13,7 @@
pub(crate) fn highlight_as_html_with_config(
db: &RootDatabase,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
file_id: FileId,
rainbow: bool,
) -> String {
@@ -60,7 +61,7 @@
pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
highlight_as_html_with_config(
db,
- HighlightConfig {
+ &HighlightConfig {
strings: true,
comments: true,
punctuation: true,
@@ -70,6 +71,7 @@
inject_doc_comment: true,
macro_bang: true,
syntactic_name_ref_highlighting: false,
+ minicore: MiniCore::default(),
},
file_id,
rainbow,
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index efc7782..7955f5a 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -4,9 +4,9 @@
use either::Either;
use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym};
+use ide_db::range_mapper::RangeMapper;
use ide_db::{
- SymbolKind, active_parameter::ActiveParameter, defs::Definition,
- documentation::docs_with_rangemap, rust_doc::is_rust_fence,
+ SymbolKind, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence,
};
use syntax::{
AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize,
@@ -16,85 +16,56 @@
use crate::{
Analysis, HlMod, HlRange, HlTag, RootDatabase,
doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
- syntax_highlighting::{HighlightConfig, highlights::Highlights, injector::Injector},
+ syntax_highlighting::{HighlightConfig, highlights::Highlights},
};
pub(super) fn ra_fixture(
hl: &mut Highlights,
sema: &Semantics<'_, RootDatabase>,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
literal: &ast::String,
expanded: &ast::String,
) -> Option<()> {
- let active_parameter =
- hir::attach_db(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?;
- let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
- attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
- path.segments()
- .zip(["rust_analyzer", "rust_fixture"])
- .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
- })
- });
- if !has_rust_fixture_attr {
- return None;
- }
- let value = literal.value().ok()?;
+ let (analysis, fixture_analysis) = Analysis::from_ra_fixture_with_on_cursor(
+ sema,
+ literal.clone(),
+ expanded,
+ config.minicore,
+ &mut |range| {
+ hl.add(HlRange {
+ range,
+ highlight: HlTag::Keyword | HlMod::Injected,
+ binding_hash: None,
+ });
+ },
+ )?;
if let Some(range) = literal.open_quote_text_range() {
hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
}
- let mut inj = Injector::default();
-
- let mut text = &*value;
- let mut offset: TextSize = 0.into();
-
- while !text.is_empty() {
- let marker = "$0";
- let idx = text.find(marker).unwrap_or(text.len());
- let (chunk, next) = text.split_at(idx);
- inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
-
- text = next;
- offset += TextSize::of(chunk);
-
- if let Some(next) = text.strip_prefix(marker) {
- if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
- hl.add(HlRange {
- range,
- highlight: HlTag::Keyword | HlMod::Injected,
- binding_hash: None,
- });
- }
-
- text = next;
-
- let marker_len = TextSize::of(marker);
- offset += marker_len;
- }
- }
-
- let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
-
- for mut hl_range in analysis
- .highlight(
- HighlightConfig {
- syntactic_name_ref_highlighting: false,
- comments: true,
- punctuation: true,
- operator: true,
- strings: true,
- specialize_punctuation: config.specialize_punctuation,
- specialize_operator: config.operator,
- inject_doc_comment: config.inject_doc_comment,
- macro_bang: config.macro_bang,
- },
- tmp_file_id,
- )
- .unwrap()
- {
- for range in inj.map_range_up(hl_range.range) {
- if let Some(range) = literal.map_range_up(range) {
+ for tmp_file_id in fixture_analysis.files() {
+ for mut hl_range in analysis
+ .highlight(
+ HighlightConfig {
+ syntactic_name_ref_highlighting: false,
+ comments: true,
+ punctuation: true,
+ operator: true,
+ strings: true,
+ specialize_punctuation: config.specialize_punctuation,
+ specialize_operator: config.operator,
+ inject_doc_comment: config.inject_doc_comment,
+ macro_bang: config.macro_bang,
+ // What if there is a fixture inside a fixture? It's fixtures all the way down.
+ // (In fact, we have a fixture inside a fixture in our test suite!)
+ minicore: config.minicore,
+ },
+ tmp_file_id,
+ )
+ .unwrap()
+ {
+ for range in fixture_analysis.map_range_up(tmp_file_id, hl_range.range) {
hl_range.range = range;
hl_range.highlight |= HlMod::Injected;
hl.add(hl_range);
@@ -116,7 +87,7 @@
pub(super) fn doc_comment(
hl: &mut Highlights,
sema: &Semantics<'_, RootDatabase>,
- config: HighlightConfig,
+ config: &HighlightConfig<'_>,
src_file_id: EditionedFileId,
node: &SyntaxNode,
) {
@@ -128,39 +99,37 @@
// Extract intra-doc links and emit highlights for them.
if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) {
- hir::attach_db(sema.db, || {
- extract_definitions_from_docs(&docs)
- .into_iter()
- .filter_map(|(range, link, ns)| {
- doc_mapping
- .map(range)
- .filter(|(mapping, _)| mapping.file_id == src_file_id)
- .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
- Some(mapped_range).zip(resolve_doc_path_for_def(
- sema.db,
- def,
- &link,
- ns,
- attr_id.is_inner_attr(),
- ))
- })
- })
- .for_each(|(range, def)| {
- hl.add(HlRange {
- range,
- highlight: module_def_to_hl_tag(def)
- | HlMod::Documentation
- | HlMod::Injected
- | HlMod::IntraDocLink,
- binding_hash: None,
+ extract_definitions_from_docs(&docs)
+ .into_iter()
+ .filter_map(|(range, link, ns)| {
+ doc_mapping
+ .map(range)
+ .filter(|(mapping, _)| mapping.file_id == src_file_id)
+ .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+ Some(mapped_range).zip(resolve_doc_path_for_def(
+ sema.db,
+ def,
+ &link,
+ ns,
+ attr_id.is_inner_attr(),
+ ))
})
+ })
+ .for_each(|(range, def)| {
+ hl.add(HlRange {
+ range,
+ highlight: module_def_to_hl_tag(def)
+ | HlMod::Documentation
+ | HlMod::Injected
+ | HlMod::IntraDocLink,
+ binding_hash: None,
})
- });
+ })
}
// Extract doc-test sources from the docs and calculate highlighting for them.
- let mut inj = Injector::default();
+ let mut inj = RangeMapper::default();
inj.add_unmapped("fn doctest() {\n");
let attrs_source_map = attributes.source_map(sema.db);
@@ -249,7 +218,7 @@
if let Ok(ranges) = analysis.with_db(|db| {
super::highlight(
db,
- HighlightConfig {
+ &HighlightConfig {
syntactic_name_ref_highlighting: true,
comments: true,
punctuation: true,
@@ -259,6 +228,7 @@
specialize_operator: config.operator,
inject_doc_comment: config.inject_doc_comment,
macro_bang: config.macro_bang,
+ minicore: config.minicore,
},
tmp_file_id,
None,
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
deleted file mode 100644
index c30f797..0000000
--- a/crates/ide/src/syntax_highlighting/injector.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-//! Extracts a subsequence of a text document, remembering the mapping of ranges
-//! between original and extracted texts.
-use std::ops::{self, Sub};
-
-use stdx::equal_range_by;
-use syntax::{TextRange, TextSize};
-
-#[derive(Default)]
-pub(super) struct Injector {
- buf: String,
- ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
-}
-
-impl Injector {
- pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
- let len = TextSize::of(text);
- assert_eq!(len, source_range.len());
- self.add_impl(text, Some(source_range.start()));
- }
-
- pub(super) fn add_unmapped(&mut self, text: &str) {
- self.add_impl(text, None);
- }
-
- fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
- let len = TextSize::of(text);
- let target_range = TextRange::at(TextSize::of(&self.buf), len);
- self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it))));
- self.buf.push_str(text);
- }
-
- pub(super) fn take_text(&mut self) -> String {
- std::mem::take(&mut self.buf)
- }
-
- pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
- equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| {
- let (target_range, delta) = self.ranges[i];
- let intersection = target_range.intersect(range).unwrap();
- Some(intersection + delta?)
- })
- }
-}
-
-#[derive(Clone, Copy)]
-enum Delta<T> {
- Add(T),
- Sub(T),
-}
-
-impl<T> Delta<T> {
- fn new(from: T, to: T) -> Delta<T>
- where
- T: Ord + Sub<Output = T>,
- {
- if to >= from { Delta::Add(to - from) } else { Delta::Sub(from - to) }
- }
-}
-
-impl ops::Add<Delta<TextSize>> for TextSize {
- type Output = TextSize;
-
- fn add(self, rhs: Delta<TextSize>) -> TextSize {
- match rhs {
- Delta::Add(it) => self + it,
- Delta::Sub(it) => self - it,
- }
- }
-}
-
-impl ops::Add<Delta<TextSize>> for TextRange {
- type Output = TextRange;
-
- fn add(self, rhs: Delta<TextSize>) -> TextRange {
- TextRange::at(self.start() + rhs, self.len())
- }
-}
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 4b87626..456a612 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -124,8 +124,10 @@
Bitwise,
/// +, -, *, /, +=, -=, *=, /=
Arithmetic,
- /// &&, ||, !
+ /// &&, ||
Logical,
+ /// !
+ Negation,
/// >, <, ==, >=, <=, !=
Comparison,
/// Other operators
@@ -194,6 +196,7 @@
HlOperator::Arithmetic => "arithmetic",
HlOperator::Logical => "logical",
HlOperator::Comparison => "comparison",
+ HlOperator::Negation => "negation",
HlOperator::Other => "operator",
},
HlTag::StringLiteral => "string_literal",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index d99b29c..d058191 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -148,7 +148,7 @@
<span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="comma">,</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="operator">.</span><span class="field library">0</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="negation">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
<span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
<span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 3b468ab..579c6ce 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -43,18 +43,19 @@
<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
- <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span><span class="none injected">
-</span><span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
- </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
- </span><span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
- </span><span class="brace injected">}</span><span class="none injected">
+ <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- minicore: sized
+<span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="trait default_library injected library">Sized</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span> <span class="brace injected">}</span><span class="none injected">
</span><span class="brace injected">}</span><span class="string_literal">"#</span>
<span class="parenthesis">)</span><span class="semicolon">;</span>
- <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span><span class="none injected">
-</span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
- </span><span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
- </span><span class="numeric_literal injected">92</span><span class="none injected">
- </span><span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
+ <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span>
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="numeric_literal injected">92</span><span class="none injected">
+</span> <span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
</span><span class="brace injected">}</span><span class="string_literal">"</span>
<span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
new file mode 100644
index 0000000..fc2d9a3
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
@@ -0,0 +1,61 @@
+
+<style>
+body { margin: 0; }
+pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime { color: #DFAF8F; font-style: italic; }
+.label { color: #DFAF8F; font-style: italic; }
+.comment { color: #7F9F7F; }
+.documentation { color: #629755; }
+.intra_doc_link { font-style: italic; }
+.injected { opacity: 0.65 ; }
+.struct, .enum { color: #7CB8BB; }
+.enum_variant { color: #BDE0F3; }
+.string_literal { color: #CC9393; }
+.field { color: #94BFF3; }
+.function { color: #93E0E3; }
+.parameter { color: #94BFF3; }
+.text { color: #DCDCCC; }
+.type { color: #7CB8BB; }
+.builtin_type { color: #8CD0D3; }
+.type_param { color: #DFAF8F; }
+.attribute { color: #94BFF3; }
+.numeric_literal { color: #BFEBBF; }
+.bool_literal { color: #BFE6EB; }
+.macro { color: #94BFF3; }
+.proc_macro { color: #94BFF3; text-decoration: underline; }
+.derive { color: #94BFF3; font-style: italic; }
+.module { color: #AFD8AF; }
+.value_param { color: #DCDCCC; }
+.variable { color: #DCDCCC; }
+.format_specifier { color: #CC696B; }
+.mutable { text-decoration: underline; }
+.escape_sequence { color: #94BFF3; }
+.keyword { color: #F0DFAF; font-weight: bold; }
+.control { font-style: italic; }
+.reference { font-style: italic; font-weight: bold; }
+.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+
+<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+ <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- /main.rs crate:main deps:other_crate
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">test</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="module crate_root injected library">other_crate</span><span class="operator injected">::</span><span class="module injected library">foo</span><span class="operator injected">::</span><span class="struct injected library">S</span><span class="operator injected">::</span><span class="function associated injected library static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span> <span class="variable injected">x</span><span class="semicolon injected">;</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected"> </span><span class="comment injected">//^ i128</span><span class="none injected">
+</span><span class="none injected">
+</span>@@- /lib.rs crate:other_crate
+<span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">mod</span><span class="none injected"> </span><span class="module declaration injected public">foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">struct</span><span class="none injected"> </span><span class="struct declaration injected public">S</span><span class="semicolon injected">;</span><span class="none injected">
+</span> <span class="keyword injected">impl</span><span class="none injected"> </span><span class="struct injected public">S</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span> <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected public static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">-></span><span class="none injected"> </span><span class="builtin_type injected">i128</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="numeric_literal injected">0</span><span class="none injected"> </span><span class="brace injected">}</span><span class="none injected">
+</span> <span class="brace injected">}</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected">
+</span> <span class="none injected"> </span><span class="string_literal">"#</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index 9c42401..cceb159 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -41,7 +41,7 @@
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
</style>
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
- <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">>></span> <span class="numeric_literal">1</span> <span class="bitwise"><<</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
+ <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="negation">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">>></span> <span class="numeric_literal">1</span> <span class="bitwise"><<</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">a</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
<span class="variable mutable">a</span> <span class="arithmetic mutable">+=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
<span class="variable mutable">a</span> <span class="arithmetic mutable">-=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8198701..4e84127 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,13 +1,13 @@
use std::time::Instant;
use expect_test::{ExpectFile, expect_file};
-use ide_db::SymbolKind;
+use ide_db::{MiniCore, SymbolKind};
use span::Edition;
use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture};
-const HL_CONFIG: HighlightConfig = HighlightConfig {
+const HL_CONFIG: HighlightConfig<'_> = HighlightConfig {
strings: true,
comments: true,
punctuation: true,
@@ -17,6 +17,7 @@
inject_doc_comment: true,
macro_bang: true,
syntactic_name_ref_highlighting: false,
+ minicore: MiniCore::default(),
};
#[test]
@@ -1017,6 +1018,35 @@
}
#[test]
+fn test_injection_2() {
+ check_highlighting(
+ r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn main() {
+ fixture(r#"
+@@- /main.rs crate:main deps:other_crate
+fn test() {
+ let x = other_crate::foo::S::thing();
+ x;
+} //^ i128
+
+@@- /lib.rs crate:other_crate
+pub mod foo {
+ pub struct S;
+ impl S {
+ pub fn thing() -> i128 { 0 }
+ }
+}
+ "#);
+}
+"##,
+ expect_file!["./test_data/highlight_injection_2.html"],
+ false,
+ );
+}
+
+#[test]
fn test_injection() {
check_highlighting(
r##"
@@ -1024,7 +1054,8 @@
fn main() {
fixture(r#"
-trait Foo {
+@@- minicore: sized
+trait Foo: Sized {
fn foo() {
println!("2 + 2 = {}", 4);
}
@@ -1223,7 +1254,7 @@
/// Note that the `snapshot` file is overwritten by the rendered HTML.
fn check_highlighting_with_config(
#[rust_analyzer::rust_fixture] ra_fixture: &str,
- config: HighlightConfig,
+ config: HighlightConfig<'_>,
expect: ExpectFile,
rainbow: bool,
) {
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 920bdd9..756377f 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -517,4 +517,6 @@
precision,
width,
never_type_fallback,
+ specialization,
+ min_specialization,
}
diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs
index 8bafcf4..3f90ecc 100644
--- a/crates/macros/src/lib.rs
+++ b/crates/macros/src/lib.rs
@@ -162,3 +162,42 @@
ignored
}
+
+decl_derive!(
+ [UpmapFromRaFixture] => upmap_from_ra_fixture
+);
+
+fn upmap_from_ra_fixture(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+ if let syn::Data::Union(_) = s.ast().data {
+ panic!("cannot derive on union")
+ }
+
+ s.add_bounds(synstructure::AddBounds::Generics);
+ s.bind_with(|_| synstructure::BindStyle::Move);
+ let body = s.each_variant(|vi| {
+ let bindings = vi.bindings();
+ vi.construct(|_, index| {
+ let bind = &bindings[index];
+
+ quote! {
+ ::ide_db::ra_fixture::UpmapFromRaFixture::upmap_from_ra_fixture(
+ #bind, __analysis, __virtual_file_id, __real_file_id,
+ )?
+ }
+ })
+ });
+
+ s.bound_impl(
+ quote!(::ide_db::ra_fixture::UpmapFromRaFixture),
+ quote! {
+ fn upmap_from_ra_fixture(
+ self,
+ __analysis: &::ide_db::ra_fixture::RaFixtureAnalysis,
+ __virtual_file_id: ::ide_db::ra_fixture::FileId,
+ __real_file_id: ::ide_db::ra_fixture::FileId,
+ ) -> Result<Self, ()> {
+ Ok(match self { #body })
+ }
+ },
+ )
+}
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index c7da654..8384d5b 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -19,6 +19,7 @@
tracing = { workspace = true, optional = true }
edition.workspace = true
+winnow = { version = "0.7.13", default-features = false }
[dev-dependencies]
expect-test = "1.5.1"
diff --git a/crates/parser/src/frontmatter.rs b/crates/parser/src/frontmatter.rs
new file mode 100644
index 0000000..2747db4
--- /dev/null
+++ b/crates/parser/src/frontmatter.rs
@@ -0,0 +1,348 @@
+// Copied from https://github.com/rust-lang/cargo/blob/367fd9f213750cd40317803dd0a5a3ce3f0c676d/src/cargo/util/frontmatter.rs
+#![expect(dead_code)] // avoid editing
+#![expect(unreachable_pub)] // avoid editing
+#![expect(clippy::useless_format)] // avoid editing
+
+type Span = std::ops::Range<usize>;
+
+#[derive(Debug)]
+pub struct ScriptSource<'s> {
+ /// The full file
+ raw: &'s str,
+ /// The `#!/usr/bin/env cargo` line, if present
+ shebang: Option<Span>,
+ /// The code fence opener (`---`)
+ open: Option<Span>,
+ /// Trailing text after `ScriptSource::open` that identifies the meaning of
+ /// `ScriptSource::frontmatter`
+ info: Option<Span>,
+ /// The lines between `ScriptSource::open` and `ScriptSource::close`
+ frontmatter: Option<Span>,
+ /// The code fence closer (`---`)
+ close: Option<Span>,
+ /// All content after the frontmatter and shebang
+ content: Span,
+}
+
+impl<'s> ScriptSource<'s> {
+ pub fn parse(raw: &'s str) -> Result<Self, FrontmatterError> {
+ use winnow::stream::FindSlice as _;
+ use winnow::stream::Location as _;
+ use winnow::stream::Offset as _;
+ use winnow::stream::Stream as _;
+
+ let content_end = raw.len();
+ let mut source = Self {
+ raw,
+ shebang: None,
+ open: None,
+ info: None,
+ frontmatter: None,
+ close: None,
+ content: 0..content_end,
+ };
+
+ let mut input = winnow::stream::LocatingSlice::new(raw);
+
+ if let Some(shebang_end) = strip_shebang(input.as_ref()) {
+ let shebang_start = input.current_token_start();
+ let _ = input.next_slice(shebang_end);
+ let shebang_end = input.current_token_start();
+ source.shebang = Some(shebang_start..shebang_end);
+ source.content = shebang_end..content_end;
+ }
+
+ // Whitespace may precede a frontmatter but must end with a newline
+ if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+ let _ = input.next_slice(nl_end);
+ }
+
+ // Opens with a line that starts with 3 or more `-` followed by an optional identifier
+ const FENCE_CHAR: char = '-';
+ let fence_length = input
+ .as_ref()
+ .char_indices()
+ .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+ .unwrap_or_else(|| input.eof_offset());
+ let open_start = input.current_token_start();
+ let fence_pattern = input.next_slice(fence_length);
+ let open_end = input.current_token_start();
+ match fence_length {
+ 0 => {
+ return Ok(source);
+ }
+ 1 | 2 => {
+ // either not a frontmatter or invalid frontmatter opening
+ return Err(FrontmatterError::new(
+ format!(
+ "found {fence_length} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
+ ),
+ raw.len()..raw.len(),
+ ).push_visible_span(open_start..open_end));
+ }
+ _ => {}
+ }
+ source.open = Some(open_start..open_end);
+ let Some(info_nl) = input.find_slice("\n") else {
+ return Err(FrontmatterError::new(
+ format!("unclosed frontmatter; expected `{fence_pattern}`"),
+ raw.len()..raw.len(),
+ )
+ .push_visible_span(open_start..open_end));
+ };
+ let info = input.next_slice(info_nl.start);
+ let info = info.strip_suffix('\r').unwrap_or(info); // already excludes `\n`
+ let info = info.trim_matches(is_horizontal_whitespace);
+ if !info.is_empty() {
+ let info_start = info.offset_from(&raw);
+ let info_end = info_start + info.len();
+ source.info = Some(info_start..info_end);
+ }
+
+ // Ends with a line that starts with a matching number of `-` only followed by whitespace
+ let nl_fence_pattern = format!("\n{fence_pattern}");
+ let Some(frontmatter_nl) = input.find_slice(nl_fence_pattern.as_str()) else {
+ for len in (2..(nl_fence_pattern.len() - 1)).rev() {
+ let Some(frontmatter_nl) = input.find_slice(&nl_fence_pattern[0..len]) else {
+ continue;
+ };
+ let _ = input.next_slice(frontmatter_nl.start + 1);
+ let close_start = input.current_token_start();
+ let _ = input.next_slice(len);
+ let close_end = input.current_token_start();
+ let fewer_dashes = fence_length - len;
+ return Err(FrontmatterError::new(
+ format!(
+ "closing code fence has {fewer_dashes} less `-` than the opening fence"
+ ),
+ close_start..close_end,
+ )
+ .push_visible_span(open_start..open_end));
+ }
+ return Err(FrontmatterError::new(
+ format!("unclosed frontmatter; expected `{fence_pattern}`"),
+ raw.len()..raw.len(),
+ )
+ .push_visible_span(open_start..open_end));
+ };
+ let frontmatter_start = input.current_token_start() + 1; // skip nl from infostring
+ let _ = input.next_slice(frontmatter_nl.start + 1);
+ let frontmatter_end = input.current_token_start();
+ source.frontmatter = Some(frontmatter_start..frontmatter_end);
+ let close_start = input.current_token_start();
+ let _ = input.next_slice(fence_length);
+ let close_end = input.current_token_start();
+ source.close = Some(close_start..close_end);
+
+ let nl = input.find_slice("\n");
+ let after_closing_fence =
+ input.next_slice(nl.map(|span| span.end).unwrap_or_else(|| input.eof_offset()));
+ let content_start = input.current_token_start();
+ let extra_dashes = after_closing_fence.chars().take_while(|b| *b == FENCE_CHAR).count();
+ if 0 < extra_dashes {
+ let extra_start = close_end;
+ let extra_end = extra_start + extra_dashes;
+ return Err(FrontmatterError::new(
+ format!("closing code fence has {extra_dashes} more `-` than the opening fence"),
+ extra_start..extra_end,
+ )
+ .push_visible_span(open_start..open_end));
+ } else {
+ let after_closing_fence = strip_newline(after_closing_fence);
+ let after_closing_fence = after_closing_fence.trim_matches(is_horizontal_whitespace);
+ if !after_closing_fence.is_empty() {
+ // extra characters beyond the original fence pattern
+ let after_start = after_closing_fence.offset_from(&raw);
+ let after_end = after_start + after_closing_fence.len();
+ return Err(FrontmatterError::new(
+ format!("unexpected characters after frontmatter close"),
+ after_start..after_end,
+ )
+ .push_visible_span(open_start..open_end));
+ }
+ }
+
+ source.content = content_start..content_end;
+
+ if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+ let _ = input.next_slice(nl_end);
+ }
+ let fence_length = input
+ .as_ref()
+ .char_indices()
+ .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+ .unwrap_or_else(|| input.eof_offset());
+ if 0 < fence_length {
+ let fence_start = input.current_token_start();
+ let fence_end = fence_start + fence_length;
+ return Err(FrontmatterError::new(
+ format!("only one frontmatter is supported"),
+ fence_start..fence_end,
+ )
+ .push_visible_span(open_start..open_end)
+ .push_visible_span(close_start..close_end));
+ }
+
+ Ok(source)
+ }
+
+ pub fn shebang(&self) -> Option<&'s str> {
+ self.shebang.clone().map(|span| &self.raw[span])
+ }
+
+ pub fn shebang_span(&self) -> Option<Span> {
+ self.shebang.clone()
+ }
+
+ pub fn open_span(&self) -> Option<Span> {
+ self.open.clone()
+ }
+
+ pub fn info(&self) -> Option<&'s str> {
+ self.info.clone().map(|span| &self.raw[span])
+ }
+
+ pub fn info_span(&self) -> Option<Span> {
+ self.info.clone()
+ }
+
+ pub fn frontmatter(&self) -> Option<&'s str> {
+ self.frontmatter.clone().map(|span| &self.raw[span])
+ }
+
+ pub fn frontmatter_span(&self) -> Option<Span> {
+ self.frontmatter.clone()
+ }
+
+ pub fn close_span(&self) -> Option<Span> {
+ self.close.clone()
+ }
+
+ pub fn content(&self) -> &'s str {
+ &self.raw[self.content.clone()]
+ }
+
+ pub fn content_span(&self) -> Span {
+ self.content.clone()
+ }
+}
+
+/// Returns the index after the shebang line, if present
+pub fn strip_shebang(input: &str) -> Option<usize> {
+ // See rust-lang/rust's compiler/rustc_lexer/src/lib.rs's `strip_shebang`
+ // Shebang must start with `#!` literally, without any preceding whitespace.
+ // For simplicity we consider any line starting with `#!` a shebang,
+ // regardless of restrictions put on shebangs by specific platforms.
+ if let Some(rest) = input.strip_prefix("#!") {
+ // Ok, this is a shebang but if the next non-whitespace token is `[`,
+ // then it may be valid Rust code, so consider it Rust code.
+ //
+ // NOTE: rustc considers line and block comments to be whitespace but to avoid
+ // any more awareness of Rust grammar, we are excluding it.
+ if !rest.trim_start().starts_with('[') {
+ // No other choice than to consider this a shebang.
+ let newline_end = input.find('\n').map(|pos| pos + 1).unwrap_or(input.len());
+ return Some(newline_end);
+ }
+ }
+ None
+}
+
+/// Returns the index after any lines with only whitespace, if present
+pub fn strip_ws_lines(input: &str) -> Option<usize> {
+ let ws_end = input.find(|c| !is_whitespace(c)).unwrap_or(input.len());
+ if ws_end == 0 {
+ return None;
+ }
+
+ let nl_start = input[0..ws_end].rfind('\n')?;
+ let nl_end = nl_start + 1;
+ Some(nl_end)
+}
+
+/// True if `c` is considered a whitespace according to Rust language definition.
+/// See [Rust language reference](https://doc.rust-lang.org/reference/whitespace.html)
+/// for definitions of these classes.
+fn is_whitespace(c: char) -> bool {
+ // This is Pattern_White_Space.
+ //
+ // Note that this set is stable (ie, it doesn't change with different
+ // Unicode versions), so it's ok to just hard-code the values.
+
+ matches!(
+ c,
+ // End-of-line characters
+ | '\u{000A}' // line feed (\n)
+ | '\u{000B}' // vertical tab
+ | '\u{000C}' // form feed
+ | '\u{000D}' // carriage return (\r)
+ | '\u{0085}' // next line (from latin1)
+ | '\u{2028}' // LINE SEPARATOR
+ | '\u{2029}' // PARAGRAPH SEPARATOR
+
+ // `Default_Ignorable_Code_Point` characters
+ | '\u{200E}' // LEFT-TO-RIGHT MARK
+ | '\u{200F}' // RIGHT-TO-LEFT MARK
+
+ // Horizontal space characters
+ | '\u{0009}' // tab (\t)
+ | '\u{0020}' // space
+ )
+}
+
+/// True if `c` is considered horizontal whitespace according to Rust language definition.
+fn is_horizontal_whitespace(c: char) -> bool {
+ // This is Pattern_White_Space.
+ //
+ // Note that this set is stable (ie, it doesn't change with different
+ // Unicode versions), so it's ok to just hard-code the values.
+
+ matches!(
+ c,
+ // Horizontal space characters
+ '\u{0009}' // tab (\t)
+ | '\u{0020}' // space
+ )
+}
+
+fn strip_newline(text: &str) -> &str {
+ text.strip_suffix("\r\n").or_else(|| text.strip_suffix('\n')).unwrap_or(text)
+}
+
+#[derive(Debug)]
+pub struct FrontmatterError {
+ message: String,
+ primary_span: Span,
+ visible_spans: Vec<Span>,
+}
+
+impl FrontmatterError {
+ pub fn new(message: impl Into<String>, span: Span) -> Self {
+ Self { message: message.into(), primary_span: span, visible_spans: Vec::new() }
+ }
+
+ pub fn push_visible_span(mut self, span: Span) -> Self {
+ self.visible_spans.push(span);
+ self
+ }
+
+ pub fn message(&self) -> &str {
+ self.message.as_str()
+ }
+
+ pub fn primary_span(&self) -> Span {
+ self.primary_span.clone()
+ }
+
+ pub fn visible_spans(&self) -> &[Span] {
+ &self.visible_spans
+ }
+}
+
+impl std::fmt::Display for FrontmatterError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.message.fmt(fmt)
+ }
+}
+
+impl std::error::Error for FrontmatterError {}
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 41fd72d..76d26c1 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -430,6 +430,11 @@
// }
T!['('] if allow_calls => call_expr(p, lhs),
T!['['] if allow_calls => index_expr(p, lhs),
+ // test_err postfix_dot_expr_ambiguity
+ // fn foo() {
+ // x.
+ // ()
+ // }
T![.] => match postfix_dot_expr::<false>(p, lhs) {
Ok(it) => it,
Err(it) => {
@@ -458,6 +463,7 @@
if PATH_NAME_REF_KINDS.contains(p.nth(nth1))
&& (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::]))
+ || p.nth(nth1) == T!['(']
{
return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs));
}
@@ -526,19 +532,26 @@
lhs: CompletedMarker,
) -> CompletedMarker {
if FLOAT_RECOVERY {
- assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::])));
- } else {
assert!(
- p.at(T![.])
- && PATH_NAME_REF_KINDS.contains(p.nth(1))
- && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+ p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))
+ || p.current() == T!['(']
+ );
+ } else {
+ assert!(p.at(T![.]));
+ assert!(
+ PATH_NAME_REF_KINDS.contains(p.nth(1)) && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+ || p.nth(1) == T!['(']
);
}
let m = lhs.precede(p);
if !FLOAT_RECOVERY {
p.bump(T![.]);
}
- name_ref_mod_path(p);
+ if p.at_ts(PATH_NAME_REF_KINDS) {
+ name_ref_mod_path(p);
+ } else {
+ p.error("expected method name, field name or number");
+ }
generic_args::opt_generic_arg_list_expr(p);
if p.at(T!['(']) {
arg_list(p);
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index edc3f40..7c78ba8 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -37,10 +37,17 @@
pub fn new(edition: Edition, text: &'a str) -> LexedStr<'a> {
let _p = tracing::info_span!("LexedStr::new").entered();
let mut conv = Converter::new(edition, text);
- if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
- conv.res.push(SHEBANG, conv.offset);
- conv.offset = shebang_len;
- };
+ if let Ok(script) = crate::frontmatter::ScriptSource::parse(text) {
+ if let Some(shebang) = script.shebang_span() {
+ conv.push(SHEBANG, shebang.end - shebang.start, Vec::new());
+ }
+ if script.frontmatter().is_some() {
+ conv.push(FRONTMATTER, script.content_span().start - conv.offset, Vec::new());
+ }
+ } else if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
+ // Leave error reporting to `rustc_lexer`
+ conv.push(SHEBANG, shebang_len, Vec::new());
+ }
// Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer
// but we want to split it to two in edition <2024.
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 7963f00..53444ef 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -26,6 +26,7 @@
extern crate rustc_lexer;
mod event;
+mod frontmatter;
mod grammar;
mod input;
mod lexed_str;
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index cd6d433..9bdbe56 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -844,6 +844,10 @@
run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
}
#[test]
+ fn postfix_dot_expr_ambiguity() {
+ run_and_expect_errors("test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs");
+ }
+ #[test]
fn precise_capturing_invalid() {
run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs");
}
diff --git a/crates/parser/test_data/lexer/ok/frontmatter.rast b/crates/parser/test_data/lexer/ok/frontmatter.rast
new file mode 100644
index 0000000..2c7d3cd
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/frontmatter.rast
@@ -0,0 +1,12 @@
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/crates/parser/test_data/lexer/ok/frontmatter.rs b/crates/parser/test_data/lexer/ok/frontmatter.rs
new file mode 100644
index 0000000..be7bf74
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/frontmatter.rs
@@ -0,0 +1,8 @@
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
new file mode 100644
index 0000000..fb4787f
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
@@ -0,0 +1,13 @@
+SHEBANG "#!/usr/bin/env cargo\n"
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
new file mode 100644
index 0000000..090b771
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
@@ -0,0 +1,9 @@
+#!/usr/bin/env cargo
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/crates/parser/test_data/lexer/ok/single_line_comments.rast b/crates/parser/test_data/lexer/ok/single_line_comments.rast
index a7681e9..c4e531b 100644
--- a/crates/parser/test_data/lexer/ok/single_line_comments.rast
+++ b/crates/parser/test_data/lexer/ok/single_line_comments.rast
@@ -1,5 +1,4 @@
-SHEBANG "#!/usr/bin/env bash"
-WHITESPACE "\n"
+SHEBANG "#!/usr/bin/env bash\n"
COMMENT "// hello"
WHITESPACE "\n"
COMMENT "//! World"
diff --git a/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast b/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
index 3159a15..7ee1ecf 100644
--- a/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
@@ -1,6 +1,5 @@
SOURCE_FILE
- SHEBANG "#!/use/bin/env rusti"
- WHITESPACE "\n"
+ SHEBANG "#!/use/bin/env rusti\n"
ATTR
POUND "#"
BANG "!"
diff --git a/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
new file mode 100644
index 0000000..4ee318d
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ WHITESPACE "\n "
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 17: expected method name, field name or number
diff --git a/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
new file mode 100644
index 0000000..c1aed30
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ x.
+ ()
+}
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index 5eda5af..3a682d5 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -142,7 +142,7 @@
if let Some(&(package, workspace)) = by_id.get(package) {
cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
} else {
- never!("Received compiler message for unknown package: {}", package);
+ tracing::error!("Received compiler message for unknown package: {}", package);
}
},
progress,
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 04fb227..76ba01f 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -49,8 +49,9 @@
is_virtual_workspace: bool,
/// Whether this workspace represents the sysroot workspace.
is_sysroot: bool,
- /// Environment variables set in the `.cargo/config` file.
- config_env: Env,
+ /// Environment variables set in the `.cargo/config` file and the extraEnv
+ /// configuration option.
+ env: Env,
requires_rustc_private: bool,
}
@@ -325,7 +326,7 @@
pub fn new(
mut meta: cargo_metadata::Metadata,
ws_manifest_path: ManifestPath,
- cargo_config_env: Env,
+ cargo_env: Env,
is_sysroot: bool,
) -> CargoWorkspace {
let mut pkg_by_id = FxHashMap::default();
@@ -498,7 +499,7 @@
is_virtual_workspace,
requires_rustc_private,
is_sysroot,
- config_env: cargo_config_env,
+ env: cargo_env,
}
}
@@ -589,7 +590,7 @@
}
pub fn env(&self) -> &Env {
- &self.config_env
+ &self.env
}
pub fn is_sysroot(&self) -> bool {
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index d281492..ae0458a 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -1,6 +1,7 @@
//! Cargo-like environment variables injection.
use base_db::Env;
use paths::Utf8Path;
+use rustc_hash::FxHashMap;
use toolchain::Tool;
use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile};
@@ -60,8 +61,14 @@
env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
}
-pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoConfigFile>) -> Env {
+pub(crate) fn cargo_config_env(
+ manifest: &ManifestPath,
+ config: &Option<CargoConfigFile>,
+ extra_env: &FxHashMap<String, Option<String>>,
+) -> Env {
let mut env = Env::default();
+ env.extend(extra_env.iter().filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))));
+
let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env"))
else {
return env;
@@ -72,22 +79,34 @@
let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent());
for (key, entry) in env_json {
- let serde_json::Value::Object(entry) = entry else {
- continue;
- };
- let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
- continue;
+ let value = match entry {
+ serde_json::Value::String(s) => s.clone(),
+ serde_json::Value::Object(entry) => {
+ // Each entry MUST have a `value` key.
+ let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
+ continue;
+ };
+ // If the entry already exists in the environment AND the `force` key is not set to
+ // true, then don't overwrite the value.
+ if extra_env.get(key).is_some_and(Option::is_some)
+ && !entry.get("force").and_then(|v| v.as_bool()).unwrap_or(false)
+ {
+ continue;
+ }
+
+ if entry
+ .get("relative")
+ .and_then(|v| v.as_bool())
+ .is_some_and(std::convert::identity)
+ {
+ base.join(value).to_string()
+ } else {
+ value.to_owned()
+ }
+ }
+ _ => continue,
};
- let value = if entry
- .get("relative")
- .and_then(|v| v.as_bool())
- .is_some_and(std::convert::identity)
- {
- base.join(value).to_string()
- } else {
- value.to_owned()
- };
env.insert(key, value);
}
@@ -113,7 +132,19 @@
},
"TEST": {
"value": "test"
- }
+ },
+ "FORCED": {
+ "value": "test",
+ "force": true
+ },
+ "UNFORCED": {
+ "value": "test",
+ "force": false
+ },
+ "OVERWRITTEN": {
+ "value": "test"
+ },
+ "NOT_AN_OBJECT": "value"
}
}
"#;
@@ -121,9 +152,22 @@
let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap();
let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml"));
let manifest = ManifestPath::try_from(manifest).unwrap();
- let env = cargo_config_env(&manifest, &Some(config));
+ let extra_env = [
+ ("FORCED", Some("ignored")),
+ ("UNFORCED", Some("newvalue")),
+ ("OVERWRITTEN", Some("newvalue")),
+ ("TEST", None),
+ ]
+ .iter()
+ .map(|(k, v)| (k.to_string(), v.map(ToString::to_string)))
+ .collect();
+ let env = cargo_config_env(&manifest, &Some(config), &extra_env);
assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
assert_eq!(env.get("TEST").as_deref(), Some("test"));
+ assert_eq!(env.get("FORCED").as_deref(), Some("test"));
+ assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue"));
+ assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue"));
+ assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value"));
}
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index c0a5009..5cc399b 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -30,7 +30,7 @@
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum RustLibSrcWorkspace {
- Workspace(CargoWorkspace),
+ Workspace { ws: CargoWorkspace, metadata_err: Option<String> },
Json(ProjectJson),
Stitched(stitched::Stitched),
Empty,
@@ -39,7 +39,9 @@
impl fmt::Display for RustLibSrcWorkspace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+ RustLibSrcWorkspace::Workspace { ws, .. } => {
+ write!(f, "workspace {}", ws.workspace_root())
+ }
RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
RustLibSrcWorkspace::Stitched(stitched) => {
write!(f, "stitched with {} crates", stitched.crates.len())
@@ -74,7 +76,7 @@
pub fn is_rust_lib_src_empty(&self) -> bool {
match &self.workspace {
- RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
+ RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().next().is_none(),
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
RustLibSrcWorkspace::Empty => true,
@@ -85,9 +87,16 @@
self.error.as_deref()
}
+ pub fn metadata_error(&self) -> Option<&str> {
+ match &self.workspace {
+ RustLibSrcWorkspace::Workspace { metadata_err, .. } => metadata_err.as_deref(),
+ _ => None,
+ }
+ }
+
pub fn num_packages(&self) -> usize {
match &self.workspace {
- RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
+ RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().count(),
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.len(),
RustLibSrcWorkspace::Empty => 0,
@@ -210,7 +219,6 @@
&self,
sysroot_source_config: &RustSourceWorkspaceConfig,
no_deps: bool,
- current_dir: &AbsPath,
target_dir: &Utf8Path,
progress: &dyn Fn(String),
) -> Option<RustLibSrcWorkspace> {
@@ -224,7 +232,7 @@
if fs::metadata(&library_manifest).is_ok() {
match self.load_library_via_cargo(
&library_manifest,
- current_dir,
+ src_root,
target_dir,
cargo_config,
no_deps,
@@ -294,7 +302,9 @@
&& let Some(src_root) = &self.rust_lib_src_root
{
let has_core = match &self.workspace {
- RustLibSrcWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+ RustLibSrcWorkspace::Workspace { ws: workspace, .. } => {
+ workspace.packages().any(|p| workspace[p].name == "core")
+ }
RustLibSrcWorkspace::Json(project_json) => project_json
.crates()
.filter_map(|(_, krate)| krate.display_name.clone())
@@ -333,7 +343,7 @@
// Make sure we never attempt to write to the sysroot
let locked = true;
- let (mut res, _) =
+ let (mut res, err) =
FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
.exec(target_dir, locked, progress)?;
@@ -388,7 +398,10 @@
let cargo_workspace =
CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
- Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
+ Ok(RustLibSrcWorkspace::Workspace {
+ ws: cargo_workspace,
+ metadata_err: err.map(|e| format!("{e:#}")),
+ })
}
}
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 987d381..711cdd1 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -241,7 +241,6 @@
let loaded_sysroot = sysroot.load_workspace(
&RustSourceWorkspaceConfig::default_cargo(),
false,
- &cwd,
&Utf8PathBuf::default(),
&|_| (),
);
@@ -249,7 +248,7 @@
sysroot.set_workspace(loaded_sysroot);
}
assert!(
- matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)),
+ matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace { .. }),
"got {}",
sysroot.workspace()
);
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 0649ce9..b88db41 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -383,41 +383,40 @@
toolchain.clone(),
)),
config.no_deps,
- workspace_dir,
&target_dir,
progress,
)
});
- let cargo_config_extra_env =
- s.spawn(move || cargo_config_env(cargo_toml, &config_file));
+ let cargo_env =
+ s.spawn(move || cargo_config_env(cargo_toml, &config_file, &config.extra_env));
thread::Result::Ok((
rustc_cfg.join()?,
target_data.join()?,
rustc_dir.join()?,
loaded_sysroot.join()?,
cargo_metadata.join()?,
- cargo_config_extra_env.join()?,
+ cargo_env.join()?,
))
});
- let (
- rustc_cfg,
- data_layout,
- mut rustc,
- loaded_sysroot,
- cargo_metadata,
- cargo_config_extra_env,
- ) = match join {
- Ok(it) => it,
- Err(e) => std::panic::resume_unwind(e),
- };
+ let (rustc_cfg, data_layout, mut rustc, loaded_sysroot, cargo_metadata, mut cargo_env) =
+ match join {
+ Ok(it) => it,
+ Err(e) => std::panic::resume_unwind(e),
+ };
+
+ for (key, value) in config.extra_env.iter() {
+ if let Some(value) = value {
+ cargo_env.insert(key.clone(), value.clone());
+ }
+ }
let (meta, error) = cargo_metadata.with_context(|| {
format!(
"Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
)
})?;
- let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false);
+ let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_env, false);
if let Some(loaded_sysroot) = loaded_sysroot {
tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot");
sysroot.set_workspace(loaded_sysroot);
@@ -487,7 +486,6 @@
sysroot.load_workspace(
&RustSourceWorkspaceConfig::Json(*sysroot_project),
config.no_deps,
- project_root,
&target_dir,
progress,
)
@@ -499,7 +497,6 @@
toolchain.clone(),
)),
config.no_deps,
- project_root,
&target_dir,
progress,
)
@@ -561,7 +558,6 @@
toolchain.clone(),
)),
config.no_deps,
- dir,
&target_dir,
&|_| (),
);
@@ -590,7 +586,8 @@
.unwrap_or_else(|| dir.join("target").into());
let cargo_script =
fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
- let cargo_config_extra_env = cargo_config_env(detached_file, &config_file);
+ let cargo_config_extra_env =
+ cargo_config_env(detached_file, &config_file, &config.extra_env);
(
CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
WorkspaceBuildScripts::default(),
@@ -747,7 +744,7 @@
pub fn to_roots(&self) -> Vec<PackageRoot> {
let mk_sysroot = || {
let mut r = match self.sysroot.workspace() {
- RustLibSrcWorkspace::Workspace(ws) => ws
+ RustLibSrcWorkspace::Workspace { ws, .. } => ws
.packages()
.filter_map(|pkg| {
if ws[pkg].is_local {
@@ -1093,7 +1090,13 @@
},
file_id,
)| {
- let env = env.clone().into_iter().collect();
+ let mut env = env.clone().into_iter().collect::<Env>();
+ // Override existing env vars with those from `extra_env`
+ env.extend(
+ extra_env
+ .iter()
+ .filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))),
+ );
let target_cfgs = match target.as_deref() {
Some(target) => cfg_cache.entry(target).or_insert_with(|| {
@@ -1735,7 +1738,7 @@
) -> (SysrootPublicDeps, Option<CrateBuilderId>) {
let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
match sysroot.workspace() {
- RustLibSrcWorkspace::Workspace(cargo) => {
+ RustLibSrcWorkspace::Workspace { ws: cargo, .. } => {
let (sysroot_cg, sysroot_pm) = cargo_to_crate_graph(
load,
None,
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2a9ef98..de24bc0 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -25,7 +25,7 @@
InlayHintsConfig, LineCol, RootDatabase,
};
use ide_db::{
- EditionedFileId, LineIndexDatabase, SnippetCap,
+ EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
base_db::{SourceDatabase, salsa::Database},
};
use itertools::Itertools;
@@ -345,6 +345,8 @@
self.run_term_search(&workspace, db, &vfs, &file_ids, verbosity);
}
+ hir::clear_tls_solver_cache();
+
let db = host.raw_database_mut();
db.trigger_lru_eviction();
@@ -1194,6 +1196,7 @@
closing_brace_hints_min_lines: Some(20),
fields_to_resolve: InlayFieldsToResolve::empty(),
range_exclusive_hints: true,
+ minicore: MiniCore::default(),
},
analysis.editioned_file_id_to_vfs(file_id),
None,
@@ -1203,26 +1206,25 @@
bar.finish_and_clear();
let mut bar = create_bar();
+ let annotation_config = AnnotationConfig {
+ binary_target: true,
+ annotate_runnables: true,
+ annotate_impls: true,
+ annotate_references: false,
+ annotate_method_references: false,
+ annotate_enum_variant_references: false,
+ location: ide::AnnotationLocation::AboveName,
+ minicore: MiniCore::default(),
+ };
for &file_id in file_ids {
let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
bar.set_message(move || msg.clone());
analysis
- .annotations(
- &AnnotationConfig {
- binary_target: true,
- annotate_runnables: true,
- annotate_impls: true,
- annotate_references: false,
- annotate_method_references: false,
- annotate_enum_variant_references: false,
- location: ide::AnnotationLocation::AboveName,
- },
- analysis.editioned_file_id_to_vfs(file_id),
- )
+ .annotations(&annotation_config, analysis.editioned_file_id_to_vfs(file_id))
.unwrap()
.into_iter()
.for_each(|annotation| {
- _ = analysis.resolve_annotation(annotation);
+ _ = analysis.resolve_annotation(&annotation_config, annotation);
});
bar.inc(1);
}
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index 609ebf2..2056714 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -78,7 +78,6 @@
let loaded_sysroot = sysroot.load_workspace(
&RustSourceWorkspaceConfig::default_cargo(),
false,
- &path,
&Utf8PathBuf::default(),
&|_| (),
);
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 96b6583..652c2e3 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -8,14 +8,14 @@
use cfg::{CfgAtom, CfgDiff};
use hir::Symbol;
use ide::{
- AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
- CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
- HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
- JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
- SourceRootId,
+ AnnotationConfig, AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
+ CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
+ HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+ InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+ Snippet, SnippetScope, SourceRootId,
};
use ide_db::{
- SnippetCap,
+ MiniCore, SnippetCap,
assists::ExprFillDefaultMode,
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
};
@@ -1454,6 +1454,23 @@
pub fn references(&self) -> bool {
self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
}
+
+ pub fn into_annotation_config<'a>(
+ self,
+ binary_target: bool,
+ minicore: MiniCore<'a>,
+ ) -> AnnotationConfig<'a> {
+ AnnotationConfig {
+ binary_target,
+ annotate_runnables: self.runnable(),
+ annotate_impls: self.implementations,
+ annotate_references: self.refs_adt,
+ annotate_method_references: self.method_refs,
+ annotate_enum_variant_references: self.enum_variant_refs,
+ location: self.location.into(),
+ minicore,
+ }
+ }
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -1688,11 +1705,15 @@
}
}
- pub fn call_hierarchy(&self) -> CallHierarchyConfig {
- CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned() }
+ pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
+ CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
}
- pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig<'_> {
+ pub fn completion<'a>(
+ &'a self,
+ source_root: Option<SourceRootId>,
+ minicore: MiniCore<'a>,
+ ) -> CompletionConfig<'a> {
let client_capability_fields = self.completion_resolve_support_properties();
CompletionConfig {
enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
@@ -1746,6 +1767,7 @@
})
.collect(),
exclude_traits: self.completion_excludeTraits(source_root),
+ minicore,
}
}
@@ -1820,7 +1842,7 @@
}
}
- pub fn hover(&self) -> HoverConfig {
+ pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
let mem_kind = |kind| match kind {
MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
@@ -1853,10 +1875,15 @@
None => ide::SubstTyLen::Unlimited,
},
show_drop_glue: *self.hover_dropGlue_enable(),
+ minicore,
}
}
- pub fn inlay_hints(&self) -> InlayHintsConfig {
+ pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
+ GotoDefinitionConfig { minicore }
+ }
+
+ pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
let client_capability_fields = self.inlay_hint_resolve_support_properties();
InlayHintsConfig {
@@ -1938,6 +1965,7 @@
),
implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
+ minicore,
}
}
@@ -1975,7 +2003,7 @@
self.semanticHighlighting_nonStandardTokens().to_owned()
}
- pub fn highlighting_config(&self) -> HighlightConfig {
+ pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig<'a> {
HighlightConfig {
strings: self.semanticHighlighting_strings_enable().to_owned(),
comments: self.semanticHighlighting_comments_enable().to_owned(),
@@ -1990,6 +2018,7 @@
.to_owned(),
inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
syntactic_name_ref_highlighting: false,
+ minicore,
}
}
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index b545106..73a51bb 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -12,7 +12,7 @@
use crossbeam_channel::{Receiver, Sender, select_biased, unbounded};
use ide_db::FxHashSet;
use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
use rustc_hash::FxHashMap;
use serde::Deserialize as _;
use serde_derive::Deserialize;
@@ -432,8 +432,10 @@
options
.target_dir
.as_deref()
- .unwrap_or("target".as_ref())
- .join(format!("rust-analyzer/flycheck{}", self.id)),
+ .unwrap_or(
+ Utf8Path::new("target").join("rust-analyzer").as_path(),
+ )
+ .join(format!("flycheck{}", self.id)),
),
_ => None,
},
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index ce6644f..f557dd5 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -13,7 +13,10 @@
use crossbeam_channel::{Receiver, Sender, unbounded};
use hir::ChangeWithProcMacros;
use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
-use ide_db::base_db::{Crate, ProcMacroPaths, SourceDatabase};
+use ide_db::{
+ MiniCore,
+ base_db::{Crate, ProcMacroPaths, SourceDatabase},
+};
use itertools::Itertools;
use load_cargo::SourceRootConfig;
use lsp_types::{SemanticTokens, Url};
@@ -188,6 +191,14 @@
/// This is marked true if we failed to load a crate root file at crate graph creation,
/// which will usually end up causing a bunch of incorrect diagnostics on startup.
pub(crate) incomplete_crate_graph: bool,
+
+ pub(crate) minicore: MiniCoreRustAnalyzerInternalOnly,
+}
+
+// FIXME: This should move to the VFS once the rewrite is done.
+#[derive(Debug, Clone, Default)]
+pub(crate) struct MiniCoreRustAnalyzerInternalOnly {
+ pub(crate) minicore_text: Option<String>,
}
/// An immutable snapshot of the world's state at a point in time.
@@ -204,6 +215,7 @@
// FIXME: Can we derive this from somewhere else?
pub(crate) proc_macros_loaded: bool,
pub(crate) flycheck: Arc<[FlycheckHandle]>,
+ minicore: MiniCoreRustAnalyzerInternalOnly,
}
impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -304,6 +316,8 @@
deferred_task_queue: task_queue,
incomplete_crate_graph: false,
+
+ minicore: MiniCoreRustAnalyzerInternalOnly::default(),
};
// Apply any required database inputs from the config.
this.update_configuration(config);
@@ -550,6 +564,7 @@
workspaces: Arc::clone(&self.workspaces),
analysis: self.analysis_host.analysis(),
vfs: Arc::clone(&self.vfs),
+ minicore: self.minicore.clone(),
check_fixes: Arc::clone(&self.diagnostics.check_fixes),
mem_docs: self.mem_docs.clone(),
semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
@@ -838,6 +853,14 @@
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
self.vfs.read().0.exists(file_id)
}
+
+ #[inline]
+ pub(crate) fn minicore(&self) -> MiniCore<'_> {
+ match &self.minicore.minicore_text {
+ Some(minicore) => MiniCore::new(minicore),
+ None => MiniCore::default(),
+ }
+ }
}
pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 6cb28ae..55d092f 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -7,8 +7,8 @@
use base64::{Engine, prelude::BASE64_STANDARD};
use ide::{
- AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
- FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
+ AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition,
+ FileRange, FileStructureConfig, FindAllRefsConfig, HoverAction, HoverGotoTypeData,
InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
SingleResolve, SourceChange, TextEdit,
};
@@ -811,7 +811,8 @@
let _p = tracing::info_span!("handle_goto_definition").entered();
let position =
try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
- let nav_info = match snap.analysis.goto_definition(position)? {
+ let config = snap.config.goto_definition(snap.minicore());
+ let nav_info = match snap.analysis.goto_definition(position, &config)? {
None => return Ok(None),
Some(it) => it,
};
@@ -829,7 +830,8 @@
&snap,
params.text_document_position_params.clone()
)?);
- let nav_info = match snap.analysis.goto_declaration(position)? {
+ let config = snap.config.goto_definition(snap.minicore());
+ let nav_info = match snap.analysis.goto_declaration(position, &config)? {
None => return handle_goto_definition(snap, params),
Some(it) => it,
};
@@ -1106,7 +1108,7 @@
context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
let source_root = snap.analysis.source_root_id(position.file_id)?;
- let completion_config = &snap.config.completion(Some(source_root));
+ let completion_config = &snap.config.completion(Some(source_root), snap.minicore());
// FIXME: We should fix up the position when retrying the cancelled request instead
position.offset = position.offset.min(line_index.index.len());
let items = match snap.analysis.completions(
@@ -1160,7 +1162,8 @@
};
let source_root = snap.analysis.source_root_id(file_id)?;
- let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
+ let mut forced_resolve_completions_config =
+ snap.config.completion(Some(source_root), snap.minicore());
forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
let position = FilePosition { file_id, offset };
@@ -1274,7 +1277,7 @@
};
let file_range = try_default!(from_proto::file_range(&snap, ¶ms.text_document, range)?);
- let hover = snap.config.hover();
+ let hover = snap.config.hover(snap.minicore());
let info = match snap.analysis.hover(&hover, file_range)? {
None => return Ok(None),
Some(info) => info,
@@ -1360,7 +1363,11 @@
let exclude_imports = snap.config.find_all_refs_exclude_imports();
let exclude_tests = snap.config.find_all_refs_exclude_tests();
- let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+ let Some(refs) = snap.analysis.find_all_refs(
+ position,
+ &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+ )?
+ else {
return Ok(None);
};
@@ -1615,8 +1622,8 @@
let target_spec = TargetSpec::for_file(&snap, file_id)?;
let annotations = snap.analysis.annotations(
- &AnnotationConfig {
- binary_target: target_spec
+ &lens_config.into_annotation_config(
+ target_spec
.map(|spec| {
matches!(
spec.target_kind(),
@@ -1624,13 +1631,8 @@
)
})
.unwrap_or(false),
- annotate_runnables: lens_config.runnable(),
- annotate_impls: lens_config.implementations,
- annotate_references: lens_config.refs_adt,
- annotate_method_references: lens_config.method_refs,
- annotate_enum_variant_references: lens_config.enum_variant_refs,
- location: lens_config.location.into(),
- },
+ snap.minicore(),
+ ),
file_id,
)?;
@@ -1653,7 +1655,8 @@
let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
return Ok(code_lens);
};
- let annotation = snap.analysis.resolve_annotation(annotation)?;
+ let config = snap.config.lens().into_annotation_config(false, snap.minicore());
+ let annotation = snap.analysis.resolve_annotation(&config, annotation)?;
let mut acc = Vec::new();
to_proto::code_lens(&mut acc, &snap, annotation)?;
@@ -1736,7 +1739,7 @@
range.end().min(line_index.index.len()),
);
- let inlay_hints_config = snap.config.inlay_hints();
+ let inlay_hints_config = snap.config.inlay_hints(snap.minicore());
Ok(Some(
snap.analysis
.inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1777,7 +1780,7 @@
let line_index = snap.file_line_index(file_id)?;
let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?;
- let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+ let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(snap.minicore());
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
let resolve_hints = snap.analysis.inlay_hints_resolve(
&forced_resolve_inlay_hints_config,
@@ -1816,7 +1819,8 @@
let position =
try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
- let nav_info = match snap.analysis.call_hierarchy(position)? {
+ let config = snap.config.call_hierarchy(snap.minicore());
+ let nav_info = match snap.analysis.call_hierarchy(position, &config)? {
None => return Ok(None),
Some(it) => it,
};
@@ -1842,8 +1846,8 @@
let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
- let config = snap.config.call_hierarchy();
- let call_items = match snap.analysis.incoming_calls(config, fpos)? {
+ let config = snap.config.call_hierarchy(snap.minicore());
+ let call_items = match snap.analysis.incoming_calls(&config, fpos)? {
None => return Ok(None),
Some(it) => it,
};
@@ -1881,8 +1885,8 @@
let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
let line_index = snap.file_line_index(fpos.file_id)?;
- let config = snap.config.call_hierarchy();
- let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
+ let config = snap.config.call_hierarchy(snap.minicore());
+ let call_items = match snap.analysis.outgoing_calls(&config, fpos)? {
None => return Ok(None),
Some(it) => it,
};
@@ -1916,7 +1920,7 @@
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(snap.minicore());
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1946,7 +1950,7 @@
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(snap.minicore());
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1988,7 +1992,7 @@
let text = snap.analysis.file_text(frange.file_id)?;
let line_index = snap.file_line_index(frange.file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(snap.minicore());
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -2156,7 +2160,13 @@
) -> Option<lsp_ext::CommandLinkGroup> {
if snap.config.hover_actions().references
&& snap.config.client_commands().show_reference
- && let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None)
+ && let Some(ref_search_res) = snap
+ .analysis
+ .find_all_refs(
+ *position,
+ &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+ )
+ .unwrap_or(None)
{
let uri = to_proto::url(snap, position.file_id);
let line_index = snap.file_line_index(position.file_id).ok()?;
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 84b7888..38ee9cb 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -16,7 +16,7 @@
FilePosition, TextSize,
};
use ide_db::{
- SnippetCap,
+ MiniCore, SnippetCap,
imports::insert_use::{ImportGranularity, InsertUseConfig},
};
use project_model::CargoConfig;
@@ -186,6 +186,7 @@
exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
+ minicore: MiniCore::default(),
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -240,6 +241,7 @@
exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
+ minicore: MiniCore::default(),
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -292,6 +294,7 @@
exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
+ minicore: MiniCore::default(),
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index 3c21e19..828118a 100644
--- a/crates/rust-analyzer/src/lsp/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/lsp/semantic_tokens.rs
@@ -91,6 +91,7 @@
(LIFETIME, "lifetime"),
(LOGICAL, "logical") => OPERATOR,
(MACRO_BANG, "macroBang") => MACRO,
+ (NEGATION, "negation") => OPERATOR,
(PARENTHESIS, "parenthesis"),
(PROC_MACRO, "procMacro") => MACRO,
(PUNCTUATION, "punctuation"),
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index d51ddb8..024c13e 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -16,7 +16,9 @@
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
UpdateTest,
};
-use ide_db::{FxHasher, assists, rust_doc::format_docs, source_change::ChangeAnnotationId};
+use ide_db::{
+ FxHasher, MiniCore, assists, rust_doc::format_docs, source_change::ChangeAnnotationId,
+};
use itertools::Itertools;
use paths::{Utf8Component, Utf8Prefix};
use semver::VersionReq;
@@ -270,7 +272,7 @@
);
}
- if let Some(limit) = config.completion(None).limit {
+ if let Some(limit) = config.completion(None, MiniCore::default()).limit {
res.sort_by(|item1, item2| item1.sort_text.cmp(&item2.sort_text));
res.truncate(limit);
}
@@ -400,16 +402,17 @@
set_score(&mut lsp_item, max_relevance, item.relevance);
- let imports =
- if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
- item.import_to_add
- .clone()
- .into_iter()
- .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
- .collect()
- } else {
- Vec::new()
- };
+ let imports = if config.completion(None, MiniCore::default()).enable_imports_on_the_fly
+ && !item.import_to_add.is_empty()
+ {
+ item.import_to_add
+ .clone()
+ .into_iter()
+ .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
+ .collect()
+ } else {
+ Vec::new()
+ };
let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
let ref_resolve_data = if ref_match.is_some() {
let ref_resolve_data = lsp_ext::CompletionResolveData {
@@ -493,8 +496,15 @@
.parameter_ranges()
.iter()
.map(|it| {
- let start = call_info.signature[..it.start().into()].chars().count() as u32;
- let end = call_info.signature[..it.end().into()].chars().count() as u32;
+ let start = call_info.signature[..it.start().into()]
+ .chars()
+ .map(|c| c.len_utf16())
+ .sum::<usize>() as u32;
+ let end = start
+ + call_info.signature[it.start().into()..it.end().into()]
+ .chars()
+ .map(|c| c.len_utf16())
+ .sum::<usize>() as u32;
[start, end]
})
.map(|label_offsets| lsp_types::ParameterInformation {
@@ -513,9 +523,9 @@
label.push_str(", ");
}
first = false;
- let start = label.chars().count() as u32;
+ let start = label.len() as u32;
label.push_str(param);
- let end = label.chars().count() as u32;
+ let end = label.len() as u32;
params.push(lsp_types::ParameterInformation {
label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
documentation: None,
@@ -837,6 +847,7 @@
HlOperator::Bitwise => types::BITWISE,
HlOperator::Arithmetic => types::ARITHMETIC,
HlOperator::Logical => types::LOGICAL,
+ HlOperator::Negation => types::NEGATION,
HlOperator::Comparison => types::COMPARISON,
HlOperator::Other => types::OPERATOR,
},
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3e80e8b..c0947b2 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -847,6 +847,13 @@
self.debounce_workspace_fetch();
let vfs = &mut self.vfs.write().0;
for (path, contents) in files {
+ if matches!(path.name_and_extension(), Some(("minicore", Some("rs")))) {
+ // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
+ self.minicore.minicore_text = contents
+ .as_ref()
+ .and_then(|contents| String::from_utf8(contents.clone()).ok());
+ }
+
let path = VfsPath::from(path);
// if the file is in mem docs, it's managed by the client via notifications
// so only set it if its not in there
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index ca15e6a..1475f02 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -222,6 +222,16 @@
message.push_str(err);
message.push_str("\n\n");
}
+ if let Some(err) = ws.sysroot.metadata_error() {
+ status.health |= lsp_ext::Health::Warning;
+ format_to!(
+ message,
+ "Failed to read Cargo metadata with dependencies for sysroot of `{}`: ",
+ ws.manifest_or_root()
+ );
+ message.push_str(err);
+ message.push_str("\n\n");
+ }
if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(err)), .. } = &ws.kind {
status.health |= lsp_ext::Health::Warning;
format_to!(
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index d60196d..6c1dcf3 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -2,9 +2,9 @@
#![allow(non_snake_case)]
use crate::{
- ast::{self, support, AstChildren, AstNode},
SyntaxKind::{self, *},
SyntaxNode, SyntaxToken, T,
+ ast::{self, AstChildren, AstNode, support},
};
use std::{fmt, hash};
pub struct Abi {
@@ -2262,11 +2262,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2298,11 +2294,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2334,11 +2326,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2370,11 +2358,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2406,11 +2390,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2442,11 +2422,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2478,11 +2454,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2514,11 +2486,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2550,11 +2518,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2586,11 +2550,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2622,11 +2582,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2658,11 +2614,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2694,11 +2646,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2730,11 +2678,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2766,11 +2710,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2802,11 +2742,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2838,11 +2774,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2874,11 +2806,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2910,11 +2838,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2946,11 +2870,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2982,11 +2902,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3018,11 +2934,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3054,11 +2966,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3090,11 +2998,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3126,11 +3030,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3162,11 +3062,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3198,11 +3094,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3234,11 +3126,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3270,11 +3158,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3306,11 +3190,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3342,11 +3222,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3378,11 +3254,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3414,11 +3286,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3450,11 +3318,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3486,11 +3350,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3522,11 +3382,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3558,11 +3414,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3594,11 +3446,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3630,11 +3478,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3666,11 +3510,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3702,11 +3542,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3738,11 +3574,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3774,11 +3606,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_BINDER }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3810,11 +3638,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3846,11 +3670,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3882,11 +3702,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3918,11 +3734,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3954,11 +3766,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3990,11 +3798,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4026,11 +3830,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4062,11 +3862,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4098,11 +3894,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4134,11 +3926,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4170,11 +3958,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4206,11 +3990,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4242,11 +4022,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4278,11 +4054,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4314,11 +4086,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4350,11 +4118,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4386,11 +4150,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4422,11 +4182,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4458,11 +4214,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4494,11 +4246,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4530,11 +4278,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4566,11 +4310,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4602,11 +4342,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4638,11 +4374,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4674,11 +4406,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4710,11 +4438,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4746,11 +4470,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4782,11 +4502,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4818,11 +4534,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4854,11 +4566,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4890,11 +4598,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4926,11 +4630,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4962,11 +4662,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4998,11 +4694,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5034,11 +4726,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5070,11 +4758,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == META }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5106,11 +4790,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5142,11 +4822,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5178,11 +4854,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5214,11 +4886,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5250,11 +4918,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5286,11 +4950,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5322,11 +4982,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5358,11 +5014,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5394,11 +5046,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5430,11 +5078,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5466,11 +5110,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5502,11 +5142,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5538,11 +5174,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5574,11 +5206,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5610,11 +5238,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5646,11 +5270,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5682,11 +5302,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5718,11 +5334,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5754,11 +5366,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5790,11 +5398,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5826,11 +5430,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5862,11 +5462,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5898,11 +5494,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5934,11 +5526,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5970,11 +5558,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6006,11 +5590,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6042,11 +5622,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6078,11 +5654,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6114,11 +5686,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6150,11 +5718,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6186,11 +5750,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6222,11 +5782,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6258,11 +5814,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6294,11 +5846,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6330,11 +5878,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6366,11 +5910,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6402,11 +5942,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6438,11 +5974,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_SYNTAX }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6474,11 +6006,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6510,11 +6038,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6546,11 +6070,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6582,11 +6102,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6618,11 +6134,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6654,11 +6166,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6690,11 +6198,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6726,11 +6230,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6762,11 +6262,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6798,11 +6294,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6834,11 +6326,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6870,11 +6358,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6906,11 +6390,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6942,11 +6422,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6978,11 +6454,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7014,11 +6486,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7050,11 +6518,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7086,11 +6550,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7122,11 +6582,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7158,11 +6614,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7194,11 +6646,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7230,11 +6678,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7266,11 +6710,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7302,11 +6742,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7338,11 +6774,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7374,11 +6806,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7410,11 +6838,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7446,11 +6870,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7482,11 +6902,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7518,11 +6934,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7554,11 +6966,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7590,11 +6998,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7626,11 +7030,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7662,11 +7062,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7698,11 +7094,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7734,11 +7126,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7770,11 +7158,7 @@
fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs
index b2f56c0..3dca0db 100644
--- a/crates/syntax/src/ast/generated/tokens.rs
+++ b/crates/syntax/src/ast/generated/tokens.rs
@@ -1,9 +1,9 @@
//! Generated by `cargo xtask codegen grammar`, do not edit by hand.
use crate::{
- ast::AstToken,
SyntaxKind::{self, *},
SyntaxToken,
+ ast::AstToken,
};
use std::{fmt, hash};
pub struct Byte {
@@ -17,11 +17,7 @@
impl AstToken for Byte {
fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -51,11 +47,7 @@
impl AstToken for ByteString {
fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE_STRING }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -85,11 +77,7 @@
impl AstToken for CString {
fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -119,11 +107,7 @@
impl AstToken for Char {
fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -153,11 +137,7 @@
impl AstToken for Comment {
fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -187,11 +167,7 @@
impl AstToken for FloatNumber {
fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_NUMBER }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -221,11 +197,7 @@
impl AstToken for Ident {
fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -255,11 +227,7 @@
impl AstToken for IntNumber {
fn can_cast(kind: SyntaxKind) -> bool { kind == INT_NUMBER }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -289,11 +257,7 @@
impl AstToken for String {
fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
@@ -323,11 +287,7 @@
impl AstToken for Whitespace {
fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
fn cast(syntax: SyntaxToken) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
}
fn syntax(&self) -> &SyntaxToken { &self.syntax }
}
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index d9223e8..e1a9f3a 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -201,6 +201,10 @@
None
}
}
+ fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+ let contents_range = self.text_range_between_quotes()?;
+ offset.checked_sub(contents_range.start())
+ }
}
impl IsString for ast::String {
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index a454979..a718b96 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -24,7 +24,7 @@
use span::{Edition, FileId, Span};
use stdx::itertools::Itertools;
use test_utils::{
- CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, RangeOrOffset,
+ CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, MiniCore, RangeOrOffset,
extract_range_or_offset,
};
use triomphe::Arc;
@@ -69,7 +69,12 @@
proc_macros: Vec<(String, ProcMacro)>,
) -> Self {
let mut db = Self::default();
- let fixture = ChangeFixture::parse_with_proc_macros(&db, ra_fixture, proc_macros);
+ let fixture = ChangeFixture::parse_with_proc_macros(
+ &db,
+ ra_fixture,
+ MiniCore::RAW_SOURCE,
+ proc_macros,
+ );
fixture.change.apply(&mut db);
assert!(fixture.file_position.is_none());
db
@@ -112,8 +117,10 @@
pub struct ChangeFixture {
pub file_position: Option<(EditionedFileId, RangeOrOffset)>,
+ pub file_lines: Vec<usize>,
pub files: Vec<EditionedFileId>,
pub change: ChangeWithProcMacros,
+ pub sysroot_files: Vec<FileId>,
}
const SOURCE_ROOT_PREFIX: &str = "/";
@@ -123,12 +130,13 @@
db: &dyn salsa::Database,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) -> ChangeFixture {
- Self::parse_with_proc_macros(db, ra_fixture, Vec::new())
+ Self::parse_with_proc_macros(db, ra_fixture, MiniCore::RAW_SOURCE, Vec::new())
}
pub fn parse_with_proc_macros(
db: &dyn salsa::Database,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
+ minicore_raw: &str,
mut proc_macro_defs: Vec<(String, ProcMacro)>,
) -> ChangeFixture {
let FixtureWithProjectMeta {
@@ -149,6 +157,8 @@
let mut source_change = FileChange::default();
let mut files = Vec::new();
+ let mut sysroot_files = Vec::new();
+ let mut file_lines = Vec::new();
let mut crate_graph = CrateGraphBuilder::default();
let mut crates = FxIndexMap::default();
let mut crate_deps = Vec::new();
@@ -173,6 +183,8 @@
let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()));
for entry in fixture {
+ file_lines.push(entry.line);
+
let mut range_or_offset = None;
let text = if entry.text.contains(CURSOR_MARKER) {
if entry.text.contains(ESCAPED_CURSOR_MARKER) {
@@ -240,7 +252,7 @@
assert!(default_crate_root.is_none());
default_crate_root = Some(file_id);
default_edition = meta.edition;
- default_cfg.extend(meta.cfg.into_iter());
+ default_cfg.append(meta.cfg);
default_env.extend_from_other(&meta.env);
}
@@ -259,7 +271,9 @@
fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_owned()));
roots.push(SourceRoot::new_library(fs));
- source_change.change_file(core_file, Some(mini_core.source_code()));
+ sysroot_files.push(core_file);
+
+ source_change.change_file(core_file, Some(mini_core.source_code(minicore_raw)));
let core_crate = crate_graph.add_crate_root(
core_file,
@@ -348,6 +362,8 @@
);
roots.push(SourceRoot::new_library(fs));
+ sysroot_files.push(proc_lib_file);
+
source_change.change_file(proc_lib_file, Some(source));
let all_crates = crate_graph.iter().collect::<Vec<_>>();
@@ -396,7 +412,7 @@
change.source_change.set_roots(roots);
change.source_change.set_crate_graph(crate_graph);
- ChangeFixture { file_position, files, change }
+ ChangeFixture { file_position, file_lines, files, change, sysroot_files }
}
}
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index c024089..559894e 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -132,13 +132,17 @@
pub library: bool,
/// Actual file contents. All meta comments are stripped.
pub text: String,
+ /// The line number in the original fixture of the beginning of this fixture.
+ pub line: usize,
}
+#[derive(Debug)]
pub struct MiniCore {
activated_flags: Vec<String>,
valid_flags: Vec<String>,
}
+#[derive(Debug)]
pub struct FixtureWithProjectMeta {
pub fixture: Vec<Fixture>,
pub mini_core: Option<MiniCore>,
@@ -184,40 +188,49 @@
let mut mini_core = None;
let mut res: Vec<Fixture> = Vec::new();
let mut proc_macro_names = vec![];
+ let mut first_row = 0;
if let Some(meta) = fixture.strip_prefix("//- toolchain:") {
+ first_row += 1;
let (meta, remain) = meta.split_once('\n').unwrap();
toolchain = Some(meta.trim().to_owned());
fixture = remain;
}
if let Some(meta) = fixture.strip_prefix("//- target_data_layout:") {
+ first_row += 1;
let (meta, remain) = meta.split_once('\n').unwrap();
meta.trim().clone_into(&mut target_data_layout);
fixture = remain;
}
if let Some(meta) = fixture.strip_prefix("//- target_arch:") {
+ first_row += 1;
let (meta, remain) = meta.split_once('\n').unwrap();
meta.trim().clone_into(&mut target_arch);
fixture = remain;
}
if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
+ first_row += 1;
let (meta, remain) = meta.split_once('\n').unwrap();
proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
fixture = remain;
}
if let Some(meta) = fixture.strip_prefix("//- minicore:") {
+ first_row += 1;
let (meta, remain) = meta.split_once('\n').unwrap();
mini_core = Some(MiniCore::parse(meta));
fixture = remain;
}
- let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
+ let default =
+ if fixture.contains("//- /") { None } else { Some((first_row - 1, "//- /main.rs")) };
- for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
+ for (ix, line) in
+ default.into_iter().chain((first_row..).zip(fixture.split_inclusive('\n')))
+ {
if line.contains("//-") {
assert!(
line.starts_with("//-"),
@@ -228,7 +241,7 @@
}
if let Some(line) = line.strip_prefix("//-") {
- let meta = Self::parse_meta_line(line);
+ let meta = Self::parse_meta_line(line, (ix + 1).try_into().unwrap());
res.push(meta);
} else {
if matches!(line.strip_prefix("// "), Some(l) if l.trim().starts_with('/')) {
@@ -252,7 +265,7 @@
}
//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
- fn parse_meta_line(meta: &str) -> Fixture {
+ fn parse_meta_line(meta: &str, line: usize) -> Fixture {
let meta = meta.trim();
let mut components = meta.split_ascii_whitespace();
@@ -317,6 +330,7 @@
Fixture {
path,
text: String::new(),
+ line,
krate,
deps,
extern_prelude,
@@ -330,7 +344,7 @@
}
impl MiniCore {
- const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
+ pub const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
fn has_flag(&self, flag: &str) -> bool {
self.activated_flags.iter().any(|it| it == flag)
@@ -363,8 +377,8 @@
res
}
- pub fn available_flags() -> impl Iterator<Item = &'static str> {
- let lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+ pub fn available_flags(raw_source: &str) -> impl Iterator<Item = &str> {
+ let lines = raw_source.split_inclusive('\n');
lines
.map_while(|x| x.strip_prefix("//!"))
.skip_while(|line| !line.contains("Available flags:"))
@@ -375,9 +389,9 @@
/// Strips parts of minicore.rs which are flagged by inactive flags.
///
/// This is probably over-engineered to support flags dependencies.
- pub fn source_code(mut self) -> String {
+ pub fn source_code(mut self, raw_source: &str) -> String {
let mut buf = String::new();
- let mut lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+ let mut lines = raw_source.split_inclusive('\n');
let mut implications = Vec::new();
diff --git a/crates/vfs/src/path_interner.rs b/crates/vfs/src/path_interner.rs
index 64f5197..225bfc7 100644
--- a/crates/vfs/src/path_interner.rs
+++ b/crates/vfs/src/path_interner.rs
@@ -28,7 +28,7 @@
/// - Else, returns a newly allocated id.
pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
let (id, _added) = self.map.insert_full(path);
- assert!(id < u32::MAX as usize);
+ assert!(id < FileId::MAX as usize);
FileId(id as u32)
}
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e35a159..6dd4485 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -21,6 +21,7 @@
"@stylistic/eslint-plugin": "^4.1.0",
"@stylistic/eslint-plugin-js": "^4.1.0",
"@tsconfig/strictest": "^2.0.5",
+ "@types/lodash": "^4.17.20",
"@types/node": "~22.13.4",
"@types/vscode": "~1.93.0",
"@typescript-eslint/eslint-plugin": "^8.25.0",
@@ -1388,6 +1389,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/node": {
"version": "22.13.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index 7068723..d659421 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -58,6 +58,7 @@
"@stylistic/eslint-plugin": "^4.1.0",
"@stylistic/eslint-plugin-js": "^4.1.0",
"@tsconfig/strictest": "^2.0.5",
+ "@types/lodash": "^4.17.20",
"@types/node": "~22.13.4",
"@types/vscode": "~1.93.0",
"@typescript-eslint/eslint-plugin": "^8.25.0",
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 073ff2f..cb71a01 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -13,7 +13,7 @@
export async function createClient(
traceOutputChannel: vscode.OutputChannel,
outputChannel: vscode.OutputChannel,
- initializationOptions: vscode.WorkspaceConfiguration,
+ initializationOptions: lc.LanguageClientOptions["initializationOptions"],
serverOptions: lc.ServerOptions,
config: Config,
unlinkedFiles: vscode.Uri[],
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 3b1b076..5dc2c41 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -4,7 +4,7 @@
import * as vscode from "vscode";
import { expectNotUndefined, log, normalizeDriveLetter, unwrapUndefinable } from "./util";
import type { Env } from "./util";
-import type { Disposable } from "vscode";
+import { cloneDeep, get, pickBy, set } from "lodash";
export type RunnableEnvCfgItem = {
mask?: string;
@@ -12,13 +12,25 @@
platform?: string | string[];
};
+export type ConfigurationTree = { [key: string]: ConfigurationValue };
+export type ConfigurationValue =
+ | undefined
+ | null
+ | boolean
+ | number
+ | string
+ | ConfigurationValue[]
+ | ConfigurationTree;
+
type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
export class Config {
readonly extensionId = "rust-lang.rust-analyzer";
- configureLang: vscode.Disposable | undefined;
- readonly rootSection = "rust-analyzer";
+ configureLang: vscode.Disposable | undefined;
+ workspaceState: vscode.Memento;
+
+ private readonly rootSection = "rust-analyzer";
private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map(
(opt) => `${this.rootSection}.${opt}`,
);
@@ -27,8 +39,13 @@
(opt) => `${this.rootSection}.${opt}`,
);
- constructor(disposables: Disposable[]) {
- vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, disposables);
+ constructor(ctx: vscode.ExtensionContext) {
+ this.workspaceState = ctx.workspaceState;
+ vscode.workspace.onDidChangeConfiguration(
+ this.onDidChangeConfiguration,
+ this,
+ ctx.subscriptions,
+ );
this.refreshLogging();
this.configureLanguage();
}
@@ -37,6 +54,44 @@
this.configureLang?.dispose();
}
+ private readonly extensionConfigurationStateKey = "extensionConfigurations";
+
+ /// Returns the rust-analyzer-specific workspace configuration, incl. any
+ /// configuration items overridden by (present) extensions.
+ get extensionConfigurations(): Record<string, Record<string, unknown>> {
+ return pickBy(
+ this.workspaceState.get<Record<string, ConfigurationTree>>(
+ "extensionConfigurations",
+ {},
+ ),
+ // ignore configurations from disabled/removed extensions
+ (_, extensionId) => vscode.extensions.getExtension(extensionId) !== undefined,
+ );
+ }
+
+ async addExtensionConfiguration(
+ extensionId: string,
+ configuration: Record<string, unknown>,
+ ): Promise<void> {
+ const oldConfiguration = this.cfg;
+
+ const extCfgs = this.extensionConfigurations;
+ extCfgs[extensionId] = configuration;
+ await this.workspaceState.update(this.extensionConfigurationStateKey, extCfgs);
+
+ const newConfiguration = this.cfg;
+ const prefix = `${this.rootSection}.`;
+ await this.onDidChangeConfiguration({
+ affectsConfiguration(section: string, _scope?: vscode.ConfigurationScope): boolean {
+ return (
+ section.startsWith(prefix) &&
+ get(oldConfiguration, section.slice(prefix.length)) !==
+ get(newConfiguration, section.slice(prefix.length))
+ );
+ },
+ });
+ }
+
private refreshLogging() {
log.info(
"Extension version:",
@@ -176,10 +231,36 @@
// We don't do runtime config validation here for simplicity. More on stackoverflow:
// https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
- private get cfg(): vscode.WorkspaceConfiguration {
+ // Returns the raw configuration for rust-analyzer as returned by vscode. This
+ // should only be used when modifications to the user/workspace configuration
+ // are required.
+ private get rawCfg(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(this.rootSection);
}
+ // Returns the final configuration to use, with extension configuration overrides merged in.
+ public get cfg(): ConfigurationTree {
+ const finalConfig = cloneDeep<ConfigurationTree>(this.rawCfg);
+ for (const [extensionId, items] of Object.entries(this.extensionConfigurations)) {
+ for (const [k, v] of Object.entries(items)) {
+ const i = this.rawCfg.inspect(k);
+ if (
+ i?.workspaceValue !== undefined ||
+ i?.workspaceFolderValue !== undefined ||
+ i?.globalValue !== undefined
+ ) {
+ log.trace(
+ `Ignoring configuration override for ${k} from extension ${extensionId}`,
+ );
+ continue;
+ }
+ log.trace(`Extension ${extensionId} overrides configuration ${k} to `, v);
+ set(finalConfig, k, v);
+ }
+ }
+ return finalConfig;
+ }
+
/**
* Beware that postfix `!` operator erases both `null` and `undefined`.
* This is why the following doesn't work as expected:
@@ -187,7 +268,6 @@
* ```ts
* const nullableNum = vscode
* .workspace
- * .getConfiguration
* .getConfiguration("rust-analyzer")
* .get<number | null>(path)!;
*
@@ -197,7 +277,7 @@
* So this getter handles this quirk by not requiring the caller to use postfix `!`
*/
private get<T>(path: string): T | undefined {
- return prepareVSCodeConfig(this.cfg.get<T>(path));
+ return prepareVSCodeConfig(get(this.cfg, path)) as T;
}
get serverPath() {
@@ -223,7 +303,7 @@
}
async toggleCheckOnSave() {
- const config = this.cfg.inspect<boolean>("checkOnSave") ?? { key: "checkOnSave" };
+ const config = this.rawCfg.inspect<boolean>("checkOnSave") ?? { key: "checkOnSave" };
let overrideInLanguage;
let target;
let value;
@@ -249,7 +329,12 @@
overrideInLanguage = config.defaultLanguageValue;
value = config.defaultValue || config.defaultLanguageValue;
}
- await this.cfg.update("checkOnSave", !(value || false), target || null, overrideInLanguage);
+ await this.rawCfg.update(
+ "checkOnSave",
+ !(value || false),
+ target || null,
+ overrideInLanguage,
+ );
}
get problemMatcher(): string[] {
@@ -367,26 +452,24 @@
}
async setAskBeforeUpdateTest(value: boolean) {
- await this.cfg.update("runnables.askBeforeUpdateTest", value, true);
+ await this.rawCfg.update("runnables.askBeforeUpdateTest", value, true);
}
}
-export function prepareVSCodeConfig<T>(resp: T): T {
+export function prepareVSCodeConfig(resp: ConfigurationValue): ConfigurationValue {
if (Is.string(resp)) {
- return substituteVSCodeVariableInString(resp) as T;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } else if (resp && Is.array<any>(resp)) {
+ return substituteVSCodeVariableInString(resp);
+ } else if (resp && Is.array(resp)) {
return resp.map((val) => {
return prepareVSCodeConfig(val);
- }) as T;
+ });
} else if (resp && typeof resp === "object") {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const res: { [key: string]: any } = {};
+ const res: ConfigurationTree = {};
for (const key in resp) {
const val = resp[key];
res[key] = prepareVSCodeConfig(val);
}
- return res as T;
+ return res;
}
return resp;
}
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index e55754f..a7b7be0 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -125,7 +125,7 @@
extCtx.subscriptions.push(this);
this.version = extCtx.extension.packageJSON.version ?? "<unknown>";
this._serverVersion = "<not running>";
- this.config = new Config(extCtx.subscriptions);
+ this.config = new Config(extCtx);
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
this.updateStatusBarVisibility(vscode.window.activeTextEditor);
this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) =>
@@ -150,6 +150,13 @@
});
}
+ async addConfiguration(
+ extensionId: string,
+ configuration: Record<string, unknown>,
+ ): Promise<void> {
+ await this.config.addExtensionConfiguration(extensionId, configuration);
+ }
+
dispose() {
this.config.dispose();
this.statusBar.dispose();
@@ -230,7 +237,7 @@
debug: run,
};
- let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+ let rawInitializationOptions = this.config.cfg;
if (this.workspace.kind === "Detached Files") {
rawInitializationOptions = {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 9962985..190f586 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -13,6 +13,12 @@
export interface RustAnalyzerExtensionApi {
// FIXME: this should be non-optional
readonly client?: lc.LanguageClient;
+
+ // Allows adding a configuration override from another extension.
+ // `extensionId` is used to only merge configuration override from present
+ // extensions. `configuration` is map of rust-analyzer-specific setting
+ // overrides, e.g., `{"cargo.cfgs": ["foo", "bar"]}`.
+ addConfiguration(extensionId: string, configuration: Record<string, unknown>): Promise<void>;
}
export async function deactivate() {
diff --git a/rustfmt.toml b/rustfmt.toml
index 20bf595..3ee7fda 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,2 +1,3 @@
+edition = "2024"
reorder_modules = true
use_small_heuristics = "Max"
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 72f6215..8f70a18 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -49,6 +49,9 @@
/// build in release with debug info set to 2.
optional --dev-rel
+ /// Make `never!()`, `always!()` etc. panic instead of just logging an error.
+ optional --force-always-assert
+
/// Apply PGO optimizations
optional --pgo pgo: PgoTrainingCrate
}
@@ -124,6 +127,7 @@
pub jemalloc: bool,
pub proc_macro_server: bool,
pub dev_rel: bool,
+ pub force_always_assert: bool,
pub pgo: Option<PgoTrainingCrate>,
}
@@ -300,7 +304,12 @@
} else {
Malloc::System
};
- Some(ServerOpt { malloc, dev_rel: self.dev_rel, pgo: self.pgo.clone() })
+ Some(ServerOpt {
+ malloc,
+ dev_rel: self.dev_rel,
+ pgo: self.pgo.clone(),
+ force_always_assert: self.force_always_assert,
+ })
}
pub(crate) fn proc_macro_server(&self) -> Option<ProcMacroServerOpt> {
if !self.proc_macro_server {
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index b794f53..975e361 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -39,6 +39,18 @@
pub(crate) malloc: Malloc,
pub(crate) dev_rel: bool,
pub(crate) pgo: Option<PgoTrainingCrate>,
+ pub(crate) force_always_assert: bool,
+}
+
+impl ServerOpt {
+ fn to_features(&self) -> Vec<&'static str> {
+ let mut features = Vec::new();
+ features.extend(self.malloc.to_features());
+ if self.force_always_assert {
+ features.extend(["--features", "force-always-assert"]);
+ }
+ features
+ }
}
pub(crate) struct ProcMacroServerOpt {
@@ -136,7 +148,7 @@
}
fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> {
- let features = opts.malloc.to_features();
+ let features = &opts.to_features();
let profile = if opts.dev_rel { "dev-rel" } else { "release" };
let mut install_cmd = cmd!(
@@ -148,7 +160,7 @@
let target = detect_target(sh);
let build_cmd = cmd!(
sh,
- "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked --features force-always-assert {features...}"
+ "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked {features...}"
);
let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?;
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index d06a25c..13cb44e 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -43,7 +43,7 @@
.unwrap_or_default();
let tags = cmd!(sh, "git tag --list").read()?;
- let prev_tag = tags.lines().filter(|line| is_release_tag(line)).next_back().unwrap();
+ let prev_tag = tags.lines().rfind(|line| is_release_tag(line)).unwrap();
let contents = changelog::get_changelog(sh, changelog_n, &commit, prev_tag, &today)?;
let path = changelog_dir.join(format!("{today}-changelog-{changelog_n}.adoc"));
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index 0462835..40997eb 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -259,7 +259,7 @@
}
fn is_exclude_file(d: &Path) -> bool {
- let file_names = ["tests.rs", "famous_defs_fixture.rs"];
+ let file_names = ["tests.rs", "famous_defs_fixture.rs", "frontmatter.rs"];
d.file_name()
.unwrap_or_default()