Merge pull request #4001 from rust-lang/rustup-2024-10-30

Automatic Rustup
This commit is contained in:
Ralf Jung 2024-10-30 08:34:51 +00:00 committed by GitHub
commit 17e8a43e68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
257 changed files with 14349 additions and 6284 deletions

View file

@ -13,5 +13,5 @@ max_line_length = 100
[*.md]
indent_size = 2
[*.{yml, yaml}]
[*.{yml,yaml}]
indent_size = 2

View file

@ -1,14 +1,10 @@
# Please make sure that the `needs` fields for both `end-success` and `end-failure`
# Please make sure that the `needs` field for the `conclusion` job
# are updated when adding new jobs!
name: CI
on:
pull_request:
push:
branches:
- auto
- try
- automation/bors/try
merge_group:
env:
CARGO_INCREMENTAL: 0
@ -104,11 +100,11 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
- name: Run analysis-stats on rust std library
- name: Run analysis-stats on the rust standard libraries
if: matrix.os == 'ubuntu-latest'
env:
RUSTC_BOOTSTRAP: 1
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
RUSTC_BOOTSTRAP: 1
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/
- name: clippy
if: matrix.os == 'windows-latest'
@ -237,20 +233,21 @@ jobs:
- name: check for typos
run: typos
end-success:
name: bors build finished
if: github.event.pusher.name == 'bors' && success()
runs-on: ubuntu-latest
conclusion:
needs: [rust, rust-cross, typescript, typo-check]
steps:
- name: Mark the job as successful
run: exit 0
end-failure:
name: bors build finished
if: github.event.pusher.name == 'bors' && !success()
# We need to ensure this job does *not* get skipped if its dependencies fail,
# because a skipped job is considered a success by GitHub. So we have to
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
# when the workflow is canceled manually.
#
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
needs: [rust, rust-cross, typescript, typo-check]
steps:
- name: Mark the job as a failure
run: exit 1
# Manually check the status of all dependencies. `if: failure()` does not work.
- name: Conclusion
run: |
# Print the dependent jobs to see them in the CI log
jq -C <<< '${{ toJson(needs) }}'
# Check if all jobs that we depend on (in the needs array) were successful.
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'

3
.gitignore vendored
View file

@ -1,6 +1,5 @@
/target/
target/
/dist/
crates/*/target
**/*.rs.bk
**/*.rs.pending-snap
.idea/*

107
Cargo.lock generated
View file

@ -73,7 +73,7 @@ dependencies = [
"intern",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lz4_flex",
"rustc-hash",
"rustc-hash 2.0.0",
"salsa",
"semver",
"span",
@ -161,9 +161,10 @@ dependencies = [
"expect-test",
"intern",
"oorandom",
"rustc-hash",
"rustc-hash 2.0.0",
"syntax",
"syntax-bridge",
"tracing",
"tt",
]
@ -216,7 +217,7 @@ dependencies = [
"chalk-derive",
"chalk-ir",
"chalk-solve",
"rustc-hash",
"rustc-hash 1.1.0",
"tracing",
]
@ -232,7 +233,7 @@ dependencies = [
"indexmap",
"itertools",
"petgraph",
"rustc-hash",
"rustc-hash 1.1.0",
"tracing",
]
@ -513,7 +514,7 @@ dependencies = [
"hir-ty",
"intern",
"itertools",
"rustc-hash",
"rustc-hash 2.0.0",
"smallvec",
"span",
"stdx",
@ -547,7 +548,7 @@ dependencies = [
"mbe",
"ra-ap-rustc_abi",
"ra-ap-rustc_parse_format",
"rustc-hash",
"rustc-hash 2.0.0",
"rustc_apfloat",
"smallvec",
"span",
@ -556,6 +557,7 @@ dependencies = [
"syntax-bridge",
"test-fixture",
"test-utils",
"text-size",
"tracing",
"triomphe",
"tt",
@ -577,7 +579,7 @@ dependencies = [
"limit",
"mbe",
"parser",
"rustc-hash",
"rustc-hash 2.0.0",
"smallvec",
"span",
"stdx",
@ -616,7 +618,7 @@ dependencies = [
"ra-ap-rustc_abi",
"ra-ap-rustc_index",
"ra-ap-rustc_pattern_analysis",
"rustc-hash",
"rustc-hash 2.0.0",
"rustc_apfloat",
"scoped-tls",
"smallvec",
@ -670,7 +672,6 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"toolchain",
"tracing",
"triomphe",
@ -692,7 +693,6 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"tracing",
]
@ -711,7 +711,6 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"tracing",
]
@ -731,19 +730,18 @@ dependencies = [
"indexmap",
"itertools",
"limit",
"line-index 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
"nohash-hasher",
"parser",
"profile",
"rayon",
"rustc-hash",
"rustc-hash 2.0.0",
"span",
"stdx",
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"tracing",
"triomphe",
]
@ -765,7 +763,6 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"tracing",
]
@ -784,7 +781,6 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"text-edit",
"triomphe",
]
@ -834,7 +830,7 @@ version = "0.0.0"
dependencies = [
"dashmap",
"hashbrown",
"rustc-hash",
"rustc-hash 2.0.0",
"sptr",
"triomphe",
]
@ -939,7 +935,7 @@ version = "0.0.0"
[[package]]
name = "line-index"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"nohash-hasher",
"oorandom",
@ -948,9 +944,9 @@ dependencies = [
[[package]]
name = "line-index"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67d61795376ae2683928c218fda7d7d7db136fd38c06b7552904667f0d55580a"
checksum = "3e27e0ed5a392a7f5ba0b3808a2afccff16c64933312c84b57618b49d1209bd2"
dependencies = [
"nohash-hasher",
"text-size",
@ -1051,7 +1047,7 @@ dependencies = [
"intern",
"parser",
"ra-ap-rustc_lexer",
"rustc-hash",
"rustc-hash 2.0.0",
"smallvec",
"span",
"stdx",
@ -1345,7 +1341,7 @@ dependencies = [
"indexmap",
"intern",
"paths",
"rustc-hash",
"rustc-hash 2.0.0",
"serde",
"serde_json",
"span",
@ -1435,7 +1431,7 @@ dependencies = [
"itertools",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"paths",
"rustc-hash",
"rustc-hash 2.0.0",
"semver",
"serde",
"serde_json",
@ -1497,9 +1493,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_abi"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6999d098000b98415939f13158dac78cb3eeeb7b0c073847f3e4b623866e27c"
checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
dependencies = [
"bitflags 2.6.0",
"ra-ap-rustc_index",
@ -1508,9 +1504,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae9fb312d942817dab10790881f555928c1f6a11a85186e8e573ad4a86c7d3be"
checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros",
@ -1519,9 +1515,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index_macros"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "766e3990eb1066a06deefc561b5a01b32ca5c9211feea31cbf4ed50611519872"
checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
dependencies = [
"proc-macro2",
"quote",
@ -1530,9 +1526,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_lexer"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4afa98eb7889c137d5a3f1cd189089e16da04d1e4837d358a67aa3dab10ffbe"
checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
dependencies = [
"unicode-properties",
"unicode-xid",
@ -1540,9 +1536,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_parse_format"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9234c96ffb0565286790407fb7eb7f55ebf69267de4db382fdec0a17f14b0e2"
checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
@ -1550,12 +1546,12 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_pattern_analysis"
version = "0.71.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "273d5f72926a58c7eea27aebc898d1d5b32d23d2342f692a94a2cf8746aa4a2f"
checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash",
"rustc-hash 2.0.0",
"rustc_apfloat",
"smallvec",
"tracing",
@ -1640,7 +1636,7 @@ dependencies = [
"countme",
"hashbrown",
"memoffset",
"rustc-hash",
"rustc-hash 1.1.0",
"text-size",
]
@ -1680,7 +1676,7 @@ dependencies = [
"profile",
"project-model",
"rayon",
"rustc-hash",
"rustc-hash 2.0.0",
"scip",
"semver",
"serde",
@ -1717,6 +1713,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]]
name = "rustc_apfloat"
version = "0.2.1+llvm-462a31f5a5ab"
@ -1746,7 +1748,7 @@ dependencies = [
"oorandom",
"parking_lot",
"rand",
"rustc-hash",
"rustc-hash 2.0.0",
"salsa-macros",
"smallvec",
"tracing",
@ -1878,9 +1880,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "smol_str"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25"
checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d"
dependencies = [
"borsh",
"serde",
@ -1898,7 +1900,7 @@ version = "0.0.0"
dependencies = [
"hashbrown",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hash",
"rustc-hash 2.0.0",
"salsa",
"stdx",
"syntax",
@ -1967,12 +1969,11 @@ dependencies = [
"ra-ap-rustc_lexer",
"rayon",
"rowan",
"rustc-hash",
"rustc-hash 2.0.0",
"rustc_apfloat",
"smol_str",
"stdx",
"test-utils",
"text-edit",
"tracing",
"triomphe",
]
@ -1983,7 +1984,7 @@ version = "0.0.0"
dependencies = [
"intern",
"parser",
"rustc-hash",
"rustc-hash 2.0.0",
"span",
"stdx",
"syntax",
@ -2000,7 +2001,7 @@ dependencies = [
"cfg",
"hir-expand",
"intern",
"rustc-hash",
"rustc-hash 2.0.0",
"span",
"stdx",
"test-utils",
@ -2014,20 +2015,12 @@ dependencies = [
"dissimilar",
"paths",
"profile",
"rustc-hash",
"rustc-hash 2.0.0",
"stdx",
"text-size",
"tracing",
]
[[package]]
name = "text-edit"
version = "0.0.0"
dependencies = [
"itertools",
"text-size",
]
[[package]]
name = "text-size"
version = "1.1.1"
@ -2361,7 +2354,7 @@ dependencies = [
"indexmap",
"nohash-hasher",
"paths",
"rustc-hash",
"rustc-hash 2.0.0",
"stdx",
"tracing",
]
@ -2374,7 +2367,7 @@ dependencies = [
"notify",
"paths",
"rayon",
"rustc-hash",
"rustc-hash 2.0.0",
"stdx",
"tracing",
"vfs",

View file

@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"
[workspace.package]
rust-version = "1.81"
rust-version = "1.82"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
@ -79,24 +79,23 @@ span = { path = "./crates/span", version = "0.0.0" }
stdx = { path = "./crates/stdx", version = "0.0.0" }
syntax = { path = "./crates/syntax", version = "0.0.0" }
syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
text-edit = { path = "./crates/text-edit", version = "0.0.0" }
toolchain = { path = "./crates/toolchain", version = "0.0.0" }
tt = { path = "./crates/tt", version = "0.0.0" }
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" }
ra-ap-rustc_lexer = { version = "0.71.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.71.0", default-features = false }
ra-ap-rustc_index = { version = "0.71.0", default-features = false }
ra-ap-rustc_abi = { version = "0.71.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.71.0", default-features = false }
ra-ap-rustc_lexer = { version = "0.75", default-features = false }
ra-ap-rustc_parse_format = { version = "0.75", default-features = false }
ra-ap-rustc_index = { version = "0.75", default-features = false }
ra-ap-rustc_abi = { version = "0.75", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
test-fixture = { path = "./crates/test-fixture" }
test-utils = { path = "./crates/test-utils" }
# In-tree crates that are published separately and follow semver. See lib/README.md
line-index = { version = "0.1.1" }
line-index = { version = "0.1.2" }
la-arena = { version = "0.3.1" }
lsp-server = { version = "0.7.6" }
@ -136,7 +135,7 @@ process-wrap = { version = "8.0.2", features = ["std"] }
pulldown-cmark-to-cmark = "10.0.4"
pulldown-cmark = { version = "0.9.0", default-features = false }
rayon = "1.8.0"
rustc-hash = "1.1.0"
rustc-hash = "2.0.0"
semver = "1.0.14"
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"
@ -145,7 +144,7 @@ smallvec = { version = "1.10.0", features = [
"union",
"const_generics",
] }
smol_str = "0.3.1"
smol_str = "0.3.2"
snap = "1.1.0"
text-size = "1.1.1"
tracing = "0.1.40"

View file

@ -14,6 +14,7 @@ doctest = false
[dependencies]
rustc-hash.workspace = true
tracing.workspace = true
# locals deps
tt = { workspace = true, optional = true }

View file

@ -9,7 +9,7 @@ use std::fmt;
use rustc_hash::FxHashSet;
use intern::Symbol;
use intern::{sym, Symbol};
pub use cfg_expr::{CfgAtom, CfgExpr};
pub use dnf::DnfExpr;
@ -24,11 +24,17 @@ pub use dnf::DnfExpr;
/// of key and value in `key_values`.
///
/// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
#[derive(Clone, PartialEq, Eq, Default)]
#[derive(Clone, PartialEq, Eq)]
pub struct CfgOptions {
enabled: FxHashSet<CfgAtom>,
}
impl Default for CfgOptions {
fn default() -> Self {
Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) }
}
}
impl fmt::Debug for CfgOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut items = self
@ -54,23 +60,37 @@ impl CfgOptions {
}
pub fn insert_atom(&mut self, key: Symbol) {
self.enabled.insert(CfgAtom::Flag(key));
self.insert_any_atom(CfgAtom::Flag(key));
}
pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
self.enabled.insert(CfgAtom::KeyValue { key, value });
self.insert_any_atom(CfgAtom::KeyValue { key, value });
}
pub fn apply_diff(&mut self, diff: CfgDiff) {
for atom in diff.enable {
self.enabled.insert(atom);
self.insert_any_atom(atom);
}
for atom in diff.disable {
let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
if *sym == sym::true_ || *sym == sym::false_ {
tracing::error!("cannot remove `true` or `false` from cfg");
continue;
}
self.enabled.remove(&atom);
}
}
fn insert_any_atom(&mut self, atom: CfgAtom) {
let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
if *sym == sym::true_ || *sym == sym::false_ {
tracing::error!("cannot insert `true` or `false` to cfg");
return;
}
self.enabled.insert(atom);
}
pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
self.enabled.iter().map(|it| match it {
CfgAtom::Flag(key) => key,
@ -88,7 +108,7 @@ impl CfgOptions {
impl Extend<CfgAtom> for CfgOptions {
fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag));
}
}

View file

@ -29,6 +29,7 @@ smallvec.workspace = true
hashbrown.workspace = true
triomphe.workspace = true
rustc_apfloat = "0.2.0"
text-size.workspace = true
ra-ap-rustc_parse_format.workspace = true
ra-ap-rustc_abi.workspace = true

View file

@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{name::Name, ExpandError, InFile};
use la_arena::{Arena, ArenaMap, Idx, RawIdx};
use rustc_hash::FxHashMap;
@ -22,15 +23,33 @@ use crate::{
db::DefDatabase,
expander::Expander,
hir::{
dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
LabelId, Pat, PatId, RecordFieldPat, Statement,
},
item_tree::AttrOwner,
nameres::DefMap,
path::{ModPath, Path},
src::HasSource,
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
BlockId, DefWithBodyId, HasModule, Lookup,
};
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HygieneId(pub(crate) span::SyntaxContextId);
impl HygieneId {
pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);
pub fn new(ctx: span::SyntaxContextId) -> Self {
Self(ctx)
}
pub(crate) fn is_root(self) -> bool {
self.0.is_root()
}
}
/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
@ -51,8 +70,25 @@ pub struct Body {
pub self_param: Option<BindingId>,
/// The `ExprId` of the actual body expression.
pub body_expr: ExprId,
pub types: TypesMap,
/// Block expressions in this body that may contain inner items.
block_scopes: Vec<BlockId>,
/// A map from binding to its hygiene ID.
///
/// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here.
/// If a binding does not appear here it has `SyntaxContextId::ROOT`.
///
/// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent
/// expansions are attributed to their parent expansion (recursively).
binding_hygiene: FxHashMap<BindingId, HygieneId>,
/// A map from an variable usages to their hygiene ID.
///
/// Expressions that can be recorded here are single segment path, although not all single segments path refer
/// to variables and have hygiene (some refer to items, we don't know at this stage).
expr_hygiene: FxHashMap<ExprId, HygieneId>,
/// A map from a destructuring assignment possible variable usages to their hygiene ID.
pat_hygiene: FxHashMap<PatId, HygieneId>,
}
pub type ExprPtr = AstPtr<ast::Expr>;
@ -67,9 +103,12 @@ pub type LabelSource = InFile<LabelPtr>;
pub type FieldPtr = AstPtr<ast::RecordExprField>;
pub type FieldSource = InFile<FieldPtr>;
pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
pub type PatFieldSource = InFile<PatFieldPtr>;
pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
@ -83,11 +122,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
expr_map: FxHashMap<ExprSource, ExprId>,
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
expr_map: FxHashMap<ExprSource, ExprOrPatId>,
expr_map_back: ArenaMap<ExprId, ExprSource>,
pat_map: FxHashMap<PatSource, PatId>,
pat_map_back: ArenaMap<PatId, PatSource>,
pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
label_map: FxHashMap<LabelSource, LabelId>,
label_map_back: ArenaMap<LabelId, LabelSource>,
@ -100,10 +141,13 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
types: TypesSourceMap,
// FIXME: Make this a sane struct.
template_map: Option<
Box<(
// format_args!
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
// asm!
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
)>,
@ -261,6 +305,10 @@ impl Body {
pats,
bindings,
binding_owners,
binding_hygiene,
expr_hygiene,
pat_hygiene,
types,
} = self;
block_scopes.shrink_to_fit();
exprs.shrink_to_fit();
@ -268,6 +316,10 @@ impl Body {
pats.shrink_to_fit();
bindings.shrink_to_fit();
binding_owners.shrink_to_fit();
binding_hygiene.shrink_to_fit();
expr_hygiene.shrink_to_fit();
pat_hygiene.shrink_to_fit();
types.shrink_to_fit();
}
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@ -286,7 +338,8 @@ impl Body {
| Pat::Path(..)
| Pat::ConstBlock(..)
| Pat::Wild
| Pat::Missing => {}
| Pat::Missing
| Pat::Expr(_) => {}
&Pat::Bind { subpat, .. } => {
if let Some(subpat) = subpat {
f(subpat);
@ -322,6 +375,162 @@ impl Body {
None => true,
}
}
pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
let expr = &self[expr_id];
match expr {
Expr::Continue { .. }
| Expr::Const(_)
| Expr::Missing
| Expr::Path(_)
| Expr::OffsetOf(_)
| Expr::Literal(_)
| Expr::Underscore => {}
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, .. }
| AsmOperand::Out { expr: Some(expr), .. }
| AsmOperand::InOut { expr, .. } => f(*expr),
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
f(*in_expr);
if let Some(out_expr) = out_expr {
f(*out_expr);
}
}
AsmOperand::Out { expr: None, .. }
| AsmOperand::Const(_)
| AsmOperand::Label(_)
| AsmOperand::Sym(_) => (),
}),
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
f(*then_branch);
if let &Some(else_branch) = else_branch {
f(else_branch);
}
}
Expr::Let { expr, .. } => {
f(*expr);
}
Expr::Block { statements, tail, .. }
| Expr::Unsafe { statements, tail, .. }
| Expr::Async { statements, tail, .. } => {
for stmt in statements.iter() {
match stmt {
Statement::Let { initializer, else_branch, pat, .. } => {
if let &Some(expr) = initializer {
f(expr);
}
if let &Some(expr) = else_branch {
f(expr);
}
self.walk_exprs_in_pat(*pat, &mut f);
}
Statement::Expr { expr: expression, .. } => f(*expression),
Statement::Item(_) => (),
}
}
if let &Some(expr) = tail {
f(expr);
}
}
Expr::Loop { body, .. } => f(*body),
Expr::Call { callee, args, .. } => {
f(*callee);
args.iter().copied().for_each(f);
}
Expr::MethodCall { receiver, args, .. } => {
f(*receiver);
args.iter().copied().for_each(f);
}
Expr::Match { expr, arms } => {
f(*expr);
arms.iter().map(|arm| arm.expr).for_each(f);
}
Expr::Break { expr, .. }
| Expr::Return { expr }
| Expr::Yield { expr }
| Expr::Yeet { expr } => {
if let &Some(expr) = expr {
f(expr);
}
}
Expr::Become { expr } => f(*expr),
Expr::RecordLit { fields, spread, .. } => {
for field in fields.iter() {
f(field.expr);
}
if let &Some(expr) = spread {
f(expr);
}
}
Expr::Closure { body, .. } => {
f(*body);
}
Expr::BinaryOp { lhs, rhs, .. } => {
f(*lhs);
f(*rhs);
}
Expr::Range { lhs, rhs, .. } => {
if let &Some(lhs) = rhs {
f(lhs);
}
if let &Some(rhs) = lhs {
f(rhs);
}
}
Expr::Index { base, index, .. } => {
f(*base);
f(*index);
}
Expr::Field { expr, .. }
| Expr::Await { expr }
| Expr::Cast { expr, .. }
| Expr::Ref { expr, .. }
| Expr::UnaryOp { expr, .. }
| Expr::Box { expr } => {
f(*expr);
}
Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
Expr::Array(a) => match a {
Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
Array::Repeat { initializer, repeat } => {
f(*initializer);
f(*repeat)
}
},
&Expr::Assignment { target, value } => {
self.walk_exprs_in_pat(target, &mut f);
f(value);
}
}
}
pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
self.walk_pats(pat_id, &mut |pat| {
if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
f(expr);
}
});
}
fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
}
pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
}
pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
}
pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
match id {
ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
}
}
}
impl Default for Body {
@ -336,6 +545,10 @@ impl Default for Body {
block_scopes: Default::default(),
binding_owners: Default::default(),
self_param: Default::default(),
binding_hygiene: Default::default(),
expr_hygiene: Default::default(),
pat_hygiene: Default::default(),
types: Default::default(),
}
}
}
@ -372,14 +585,29 @@ impl Index<BindingId> for Body {
}
}
impl Index<TypeRefId> for Body {
type Output = TypeRef;
fn index(&self, b: TypeRefId) -> &TypeRef {
&self.types[b]
}
}
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap {
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
match id {
ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
ExprOrPatId::PatId(id) => self.pat_syntax(id),
}
}
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
}
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
let src = node.map(AstPtr::new);
self.expr_map.get(&src).cloned()
}
@ -395,7 +623,7 @@ impl BodySourceMap {
self.expansions.iter().map(|(&a, &b)| (a, b))
}
pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}
@ -428,7 +656,7 @@ impl BodySourceMap {
self.pat_field_map_back[&pat]
}
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
self.expr_map.get(&src).copied()
}
@ -442,9 +670,11 @@ impl BodySourceMap {
pub fn implicit_format_args(
&self,
node: InFile<&ast::FormatArgsExpr>,
) -> Option<&[(syntax::TextRange, Name)]> {
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
let (hygiene, names) =
self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
Some((*hygiene, &**names))
}
pub fn asm_template_args(
@ -452,8 +682,8 @@ impl BodySourceMap {
node: InFile<&ast::AsmExpr>,
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
let expr = self.expr_map.get(&src)?;
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
let expr = self.expr_map.get(&src)?.as_expr()?;
Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
}
/// Get a reference to the body source map's diagnostics.
@ -476,6 +706,7 @@ impl BodySourceMap {
template_map,
diagnostics,
binding_definitions,
types,
} = self;
if let Some(template_map) = template_map {
template_map.0.shrink_to_fit();
@ -492,14 +723,6 @@ impl BodySourceMap {
expansions.shrink_to_fit();
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
}
pub fn template_map(
&self,
) -> Option<&(
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>,
)> {
self.template_map.as_deref()
types.shrink_to_fit();
}
}

File diff suppressed because it is too large Load diff

View file

@ -158,9 +158,7 @@ impl ExprCollector<'_> {
AsmOperand::Const(self.collect_expr_opt(c.expr()))
}
ast::AsmOperand::AsmSym(s) => {
let Some(path) =
s.path().and_then(|p| self.expander.parse_path(self.db, p))
else {
let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
continue;
};
AsmOperand::Sym(path)

View file

@ -11,7 +11,6 @@ use crate::{
Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
};
use super::*;
@ -69,20 +68,20 @@ pub(super) fn print_body_hir(
};
if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('(');
let function_data = &db.function_data(it);
let function_data = db.function_data(it);
let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
if let Some(self_param) = body.self_param {
p.print_binding(self_param);
p.buf.push_str(": ");
if let Some(ty) = params.next() {
p.print_type_ref(ty);
p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
}
}
body.params.iter().zip(params).for_each(|(&param, ty)| {
p.print_pat(param);
p.buf.push_str(": ");
p.print_type_ref(ty);
p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
});
// remove the last ", " in param list
@ -92,7 +91,7 @@ pub(super) fn print_body_hir(
p.buf.push(')');
// return type
p.buf.push_str(" -> ");
p.print_type_ref(ret_type);
p.print_type_ref(*ret_type, &function_data.types_map);
p.buf.push(' ');
}
p.print_expr(body.body_expr);
@ -242,7 +241,7 @@ impl Printer<'_> {
Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
Expr::OffsetOf(offset_of) => {
w!(self, "builtin#offset_of(");
self.print_type_ref(&offset_of.container);
self.print_type_ref(offset_of.container, &self.body.types);
let edition = self.edition;
w!(
self,
@ -277,7 +276,7 @@ impl Printer<'_> {
w!(self, "loop ");
self.print_expr(*body);
}
Expr::Call { callee, args, is_assignee_expr: _ } => {
Expr::Call { callee, args } => {
self.print_expr(*callee);
w!(self, "(");
if !args.is_empty() {
@ -296,7 +295,7 @@ impl Printer<'_> {
if let Some(args) = generic_args {
w!(self, "::<");
let edition = self.edition;
print_generic_args(self.db, args, self, edition).unwrap();
print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
w!(self, ">");
}
w!(self, "(");
@ -372,7 +371,7 @@ impl Printer<'_> {
self.print_expr(*expr);
}
}
Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
Expr::RecordLit { path, fields, spread } => {
match path {
Some(path) => self.print_path(path),
None => w!(self, "<EFBFBD>"),
@ -391,9 +390,6 @@ impl Printer<'_> {
p.print_expr(*spread);
wln!(p);
}
if *ellipsis {
wln!(p, "..");
}
});
w!(self, "}}");
}
@ -408,7 +404,7 @@ impl Printer<'_> {
Expr::Cast { expr, type_ref } => {
self.print_expr(*expr);
w!(self, " as ");
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, &self.body.types);
}
Expr::Ref { expr, rawness, mutability } => {
w!(self, "&");
@ -466,7 +462,7 @@ impl Printer<'_> {
w!(self, ") ");
}
}
Expr::Index { base, index, is_assignee_expr: _ } => {
Expr::Index { base, index } => {
self.print_expr(*base);
w!(self, "[");
self.print_expr(*index);
@ -496,18 +492,18 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
self.print_type_ref(ty);
self.print_type_ref(*ty, &self.body.types);
}
}
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
self.print_type_ref(ret_ty);
self.print_type_ref(*ret_ty, &self.body.types);
}
self.whitespace();
self.print_expr(*body);
}
Expr::Tuple { exprs, is_assignee_expr: _ } => {
Expr::Tuple { exprs } => {
w!(self, "(");
for expr in exprs.iter() {
self.print_expr(*expr);
@ -519,7 +515,7 @@ impl Printer<'_> {
w!(self, "[");
if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
self.indented(|p| match arr {
Array::ElementList { elements, is_assignee_expr: _ } => {
Array::ElementList { elements } => {
for elem in elements.iter() {
p.print_expr(*elem);
w!(p, ", ");
@ -551,6 +547,11 @@ impl Printer<'_> {
Expr::Const(id) => {
w!(self, "const {{ /* {id:?} */ }}");
}
&Expr::Assignment { target, value } => {
self.print_pat(target);
w!(self, " = ");
self.print_expr(value);
}
}
}
@ -719,6 +720,9 @@ impl Printer<'_> {
w!(self, "const ");
self.print_expr(*c);
}
Pat::Expr(expr) => {
self.print_expr(*expr);
}
}
}
@ -729,7 +733,7 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = type_ref {
w!(self, ": ");
self.print_type_ref(ty);
self.print_type_ref(*ty, &self.body.types);
}
if let Some(init) = initializer {
w!(self, " = ");
@ -748,7 +752,7 @@ impl Printer<'_> {
}
wln!(self);
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
@ -787,14 +791,14 @@ impl Printer<'_> {
}
}
fn print_type_ref(&mut self, ty: &TypeRef) {
fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
let edition = self.edition;
print_type_ref(self.db, ty, self, edition).unwrap();
print_type_ref(self.db, ty, map, self, edition).unwrap();
}
fn print_path(&mut self, path: &Path) {
let edition = self.edition;
print_path(self.db, path, self, edition).unwrap();
print_path(self.db, path, &self.body.types, self, edition).unwrap();
}
fn print_binding(&mut self, id: BindingId) {

View file

@ -1,12 +1,12 @@
//! Name resolution for expressions.
use hir_expand::name::Name;
use hir_expand::{name::Name, MacroDefId};
use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
use triomphe::Arc;
use crate::{
body::Body,
body::{Body, HygieneId},
db::DefDatabase,
hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
BlockId, ConstBlockId, DefWithBodyId,
};
@ -22,6 +22,7 @@ pub struct ExprScopes {
#[derive(Debug, PartialEq, Eq)]
pub struct ScopeEntry {
name: Name,
hygiene: HygieneId,
binding: BindingId,
}
@ -30,6 +31,10 @@ impl ScopeEntry {
&self.name
}
pub(crate) fn hygiene(&self) -> HygieneId {
self.hygiene
}
pub fn binding(&self) -> BindingId {
self.binding
}
@ -40,6 +45,8 @@ pub struct ScopeData {
parent: Option<ScopeId>,
block: Option<BlockId>,
label: Option<(LabelId, Name)>,
// FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters.
macro_def: Option<Box<MacroDefId>>,
entries: IdxRange<ScopeEntry>,
}
@ -62,6 +69,12 @@ impl ExprScopes {
self.scopes[scope].block
}
/// If `scope` refers to a macro def scope, returns the corresponding `MacroId`.
#[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`.
pub fn macro_def(&self, scope: ScopeId) -> Option<&Box<MacroDefId>> {
self.scopes[scope].macro_def.as_ref()
}
/// If `scope` refers to a labeled expression scope, returns the corresponding `Label`.
pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> {
self.scopes[scope].label.clone()
@ -102,7 +115,7 @@ impl ExprScopes {
};
let mut root = scopes.root_scope();
if let Some(self_param) = body.self_param {
scopes.add_bindings(body, root, self_param);
scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
}
scopes.add_params_bindings(body, root, &body.params);
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
@ -114,6 +127,7 @@ impl ExprScopes {
parent: None,
block: None,
label: None,
macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@ -123,6 +137,7 @@ impl ExprScopes {
parent: Some(parent),
block: None,
label: None,
macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@ -132,6 +147,7 @@ impl ExprScopes {
parent: Some(parent),
block: None,
label,
macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@ -146,21 +162,38 @@ impl ExprScopes {
parent: Some(parent),
block,
label,
macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) {
fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box<MacroDefId>) -> ScopeId {
self.scopes.alloc(ScopeData {
parent: Some(parent),
block: None,
label: None,
macro_def: Some(macro_id),
entries: empty_entries(self.scope_entries.len()),
})
}
fn add_bindings(
&mut self,
body: &Body,
scope: ScopeId,
binding: BindingId,
hygiene: HygieneId,
) {
let Binding { name, .. } = &body.bindings[binding];
let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding });
let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
self.scopes[scope].entries =
IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
}
fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
let pattern = &body[pat];
if let Pat::Bind { id, .. } = pattern {
self.add_bindings(body, scope, *id);
if let Pat::Bind { id, .. } = *pattern {
self.add_bindings(body, scope, id, body.binding_hygiene(id));
}
pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat));
@ -206,7 +239,10 @@ fn compute_block_scopes(
Statement::Expr { expr, .. } => {
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
}
Statement::Item => (),
Statement::Item(Item::MacroDef(macro_id)) => {
*scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
}
Statement::Item(Item::Other) => (),
}
}
if let Some(expr) = tail {
@ -282,7 +318,7 @@ fn compute_expr_scopes(
*scope = scopes.new_scope(*scope);
scopes.add_pat_bindings(body, *scope, pat);
}
e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
_ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
};
}
@ -333,6 +369,8 @@ mod tests {
let expr_id = source_map
.node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
.unwrap()
.as_expr()
.unwrap();
let scope = scopes.scope_for(expr_id);
@ -488,8 +526,11 @@ fn foo() {
let expr_scope = {
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
let expr_id =
source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
let expr_id = source_map
.node_expr(InFile { file_id: file_id.into(), value: &expr_ast })
.unwrap()
.as_expr()
.unwrap();
scopes.scope_for(expr_id).unwrap()
};

View file

@ -370,3 +370,37 @@ fn f(a: i32, b: u32) -> String {
}"#]]
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
}
#[test]
fn destructuring_assignment_tuple_macro() {
// This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
// but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
// assignments start their lives as expressions. So we have to do the same.
let (db, body, def) = lower(
r#"
struct Bar();
macro_rules! m {
() => { Bar };
}
fn foo() {
m!()() = Bar();
}
"#,
);
let (_, source_map) = db.body_with_source_map(def);
assert_eq!(source_map.diagnostics(), &[]);
for (_, def_map) in body.blocks(&db) {
assert_eq!(def_map.diagnostics(), &[]);
}
expect![[r#"
fn foo() -> () {
Bar() = Bar();
}"#]]
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
}

View file

@ -6,7 +6,7 @@ use base_db::CrateId;
use hir_expand::{
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
};
use intern::{sym, Interned, Symbol};
use intern::{sym, Symbol};
use la_arena::{Idx, RawIdx};
use smallvec::SmallVec;
use syntax::{ast, Parse};
@ -25,7 +25,7 @@ use crate::{
DefMap, MacroSubNs,
},
path::ImportAlias,
type_ref::{TraitRef, TypeBound, TypeRef},
type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
visibility::RawVisibility,
AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@ -35,13 +35,14 @@ use crate::{
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
pub name: Name,
pub params: Box<[Interned<TypeRef>]>,
pub ret_type: Interned<TypeRef>,
pub params: Box<[TypeRefId]>,
pub ret_type: TypeRefId,
pub attrs: Attrs,
pub visibility: RawVisibility,
pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
pub rustc_allow_incoherent_impl: bool,
pub types_map: Arc<TypesMap>,
flags: FnFlags,
}
@ -110,13 +111,14 @@ impl FunctionData {
.filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
})
.filter_map(|(_, param)| param.type_ref.clone())
.filter_map(|(_, param)| param.type_ref)
.collect(),
ret_type: func.ret_type.clone(),
ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility,
abi: func.abi.clone(),
legacy_const_generics_indices,
types_map: func.types_map.clone(),
flags,
rustc_allow_incoherent_impl,
})
@ -148,6 +150,10 @@ impl FunctionData {
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
}
pub fn is_safe(&self) -> bool {
self.flags.contains(FnFlags::HAS_SAFE_KW)
}
pub fn is_varargs(&self) -> bool {
self.flags.contains(FnFlags::IS_VARARGS)
}
@ -178,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
pub name: Name,
pub type_ref: Option<Interned<TypeRef>>,
pub type_ref: Option<TypeRefId>,
pub visibility: RawVisibility,
pub is_extern: bool,
pub rustc_has_incoherent_inherent_impls: bool,
pub rustc_allow_incoherent_impl: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
pub bounds: Box<[Interned<TypeBound>]>,
pub bounds: Box<[TypeBound]>,
pub types_map: Arc<TypesMap>,
}
impl TypeAliasData {
@ -212,12 +219,13 @@ impl TypeAliasData {
Arc::new(TypeAliasData {
name: typ.name.clone(),
type_ref: typ.type_ref.clone(),
type_ref: typ.type_ref,
visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
rustc_has_incoherent_inherent_impls,
rustc_allow_incoherent_impl,
bounds: typ.bounds.clone(),
types_map: typ.types_map.clone(),
})
}
}
@ -339,13 +347,14 @@ impl TraitAliasData {
#[derive(Debug, PartialEq, Eq)]
pub struct ImplData {
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
pub target_trait: Option<TraitRef>,
pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
pub types_map: Arc<TypesMap>,
}
impl ImplData {
@ -364,7 +373,7 @@ impl ImplData {
let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone();
let self_ty = impl_def.self_ty.clone();
let self_ty = impl_def.self_ty;
let is_negative = impl_def.is_negative;
let is_unsafe = impl_def.is_unsafe;
@ -383,6 +392,7 @@ impl ImplData {
is_negative,
is_unsafe,
macro_calls,
types_map: impl_def.types_map.clone(),
}),
DefDiagnostics::new(diagnostics),
)
@ -528,10 +538,11 @@ impl ExternCrateDeclData {
pub struct ConstData {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub rustc_allow_incoherent_impl: bool,
pub has_body: bool,
pub types_map: Arc<TypesMap>,
}
impl ConstData {
@ -552,10 +563,11 @@ impl ConstData {
Arc::new(ConstData {
name: konst.name.clone(),
type_ref: konst.type_ref.clone(),
type_ref: konst.type_ref,
visibility,
rustc_allow_incoherent_impl,
has_body: konst.has_body,
types_map: konst.types_map.clone(),
})
}
}
@ -563,10 +575,13 @@ impl ConstData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub mutable: bool,
pub is_extern: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
pub types_map: Arc<TypesMap>,
}
impl StaticData {
@ -577,10 +592,13 @@ impl StaticData {
Arc::new(StaticData {
name: statik.name.clone(),
type_ref: statik.type_ref.clone(),
type_ref: statik.type_ref,
visibility: item_tree[statik.visibility].clone(),
mutable: statik.mutable,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
has_safe_kw: statik.has_safe_kw,
has_unsafe_kw: statik.has_unsafe_kw,
types_map: statik.types_map.clone(),
})
}
}

View file

@ -6,7 +6,7 @@ use cfg::CfgOptions;
use either::Either;
use hir_expand::name::Name;
use intern::{sym, Interned};
use intern::sym;
use la_arena::Arena;
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use triomphe::Arc;
@ -21,7 +21,7 @@ use crate::{
lang_item::LangItem,
nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
type_ref::TypeRef,
type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
};
@ -73,8 +73,8 @@ pub struct EnumVariantData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData {
Record(Arena<FieldData>),
Tuple(Arena<FieldData>),
Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Unit,
}
@ -82,7 +82,7 @@ pub enum VariantData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
}
@ -208,7 +208,7 @@ impl StructData {
}
let strukt = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@ -219,12 +219,13 @@ impl StructData {
&strukt.fields,
None,
);
let types_map = strukt.types_map.clone();
(
Arc::new(StructData {
name: strukt.name.clone(),
variant_data: Arc::new(match strukt.shape {
FieldsShape::Record => VariantData::Record(data),
FieldsShape::Tuple => VariantData::Tuple(data),
FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
repr,
@ -258,7 +259,7 @@ impl StructData {
}
let union = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@ -269,10 +270,11 @@ impl StructData {
&union.fields,
None,
);
let types_map = union.types_map.clone();
(
Arc::new(StructData {
name: union.name.clone(),
variant_data: Arc::new(VariantData::Record(data)),
variant_data: Arc::new(VariantData::Record { fields, types_map }),
repr,
visibility: item_tree[union.visibility].clone(),
flags,
@ -360,7 +362,7 @@ impl EnumVariantData {
let item_tree = loc.id.item_tree(db);
let variant = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
container.local_id,
@ -371,13 +373,14 @@ impl EnumVariantData {
&variant.fields,
Some(item_tree[loc.parent.lookup(db).id.value].visibility),
);
let types_map = variant.types_map.clone();
(
Arc::new(EnumVariantData {
name: variant.name.clone(),
variant_data: Arc::new(match variant.shape {
FieldsShape::Record => VariantData::Record(data),
FieldsShape::Tuple => VariantData::Tuple(data),
FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
}),
@ -390,11 +393,20 @@ impl VariantData {
pub fn fields(&self) -> &Arena<FieldData> {
const EMPTY: &Arena<FieldData> = &Arena::new();
match &self {
VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
_ => EMPTY,
}
}
pub fn types_map(&self) -> &TypesMap {
match &self {
VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
types_map
}
VariantData::Unit => TypesMap::EMPTY,
}
}
// FIXME: Linear lookup
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
@ -402,8 +414,8 @@ impl VariantData {
pub fn kind(&self) -> StructKind {
match self {
VariantData::Record(_) => StructKind::Record,
VariantData::Tuple(_) => StructKind::Tuple,
VariantData::Record { .. } => StructKind::Record,
VariantData::Tuple { .. } => StructKind::Tuple,
VariantData::Unit => StructKind::Unit,
}
}
@ -463,7 +475,7 @@ fn lower_field(
) -> FieldData {
FieldData {
name: field.name.clone(),
type_ref: field.type_ref.clone(),
type_ref: field.type_ref,
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
}
}

View file

@ -2,7 +2,7 @@
use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
use intern::{sym, Interned};
use intern::sym;
use la_arena::ArenaMap;
use span::{EditionedFileId, MacroCallId};
use syntax::{ast, AstPtr};
@ -18,9 +18,10 @@ use crate::{
},
generics::GenericParams,
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree},
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostics, DefMap},
type_ref::TypesSourceMap,
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[ra_salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
#[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
fn file_item_tree_with_source_map(
&self,
file_id: HirFileId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
#[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
fn block_item_tree_with_source_map(
&self,
block_id: BlockId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
#[ra_salsa::invoke(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
#[ra_salsa::invoke(GenericParams::generic_params_query)]
fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
/// If this returns `None` for the source map, that means it is the same as with the item tree.
#[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
fn generic_params_with_source_map(
&self,
def: GenericDefId,
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
// region:attrs

View file

@ -14,6 +14,7 @@ use span::SyntaxContextId;
use syntax::{ast, Parse};
use triomphe::Arc;
use crate::type_ref::{TypesMap, TypesSourceMap};
use crate::{
attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
UnresolvedMacro,
@ -49,6 +50,10 @@ impl Expander {
}
}
pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap {
self.span_map.get_or_init(|| db.span_map(self.current_file_id))
}
pub fn krate(&self) -> CrateId {
self.module.krate
}
@ -110,8 +115,19 @@ impl Expander {
mark.bomb.defuse();
}
pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
pub fn ctx<'a>(
&self,
db: &'a dyn DefDatabase,
types_map: &'a mut TypesMap,
types_source_map: &'a mut TypesSourceMap,
) -> LowerCtx<'a> {
LowerCtx::with_span_map_cell(
db,
self.current_file_id,
self.span_map.clone(),
types_map,
types_source_map,
)
}
pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
@ -138,8 +154,20 @@ impl Expander {
self.current_file_id
}
pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
pub(crate) fn parse_path(
&mut self,
db: &dyn DefDatabase,
path: ast::Path,
types_map: &mut TypesMap,
types_source_map: &mut TypesSourceMap,
) -> Option<Path> {
let ctx = LowerCtx::with_span_map_cell(
db,
self.current_file_id,
self.span_map.clone(),
types_map,
types_source_map,
);
Path::from_src(&ctx, path)
}

View file

@ -1025,7 +1025,7 @@ pub mod ast {
check_found_path(
r#"
mod bar {
mod foo { pub(super) struct S; }
mod foo { pub(crate) struct S; }
pub(crate) use foo::*;
}
$0
@ -1047,7 +1047,7 @@ $0
check_found_path(
r#"
mod bar {
mod foo { pub(super) struct S; }
mod foo { pub(crate) struct S; }
pub(crate) use foo::S as U;
}
$0

View file

@ -3,16 +3,18 @@
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.
use std::ops;
use std::{ops, sync::LazyLock};
use either::Either;
use hir_expand::{
name::{AsName, Name},
ExpandResult,
};
use intern::Interned;
use la_arena::{Arena, RawIdx};
use stdx::impl_from;
use stdx::{
impl_from,
thin_vec::{EmptyOptimizedThinVec, ThinVec},
};
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use triomphe::Arc;
@ -22,7 +24,11 @@ use crate::{
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
type_ref::{
ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
TypesSourceMap,
},
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@ -37,7 +43,7 @@ pub struct TypeParamData {
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
/// make it always be a value, giving impl trait a special name.
pub name: Option<Name>,
pub default: Option<Interned<TypeRef>>,
pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance,
}
@ -51,7 +57,7 @@ pub struct LifetimeParamData {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData {
pub name: Name,
pub ty: Interned<TypeRef>,
pub ty: TypeRefId,
pub default: Option<ConstRef>,
}
@ -161,6 +167,7 @@ pub struct GenericParams {
type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>,
where_predicates: Box<[WherePredicate]>,
pub types_map: TypesMap,
}
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
/// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate {
TypeBound {
target: WherePredicateTypeTarget,
bound: Interned<TypeBound>,
},
Lifetime {
target: LifetimeRef,
bound: LifetimeRef,
},
ForLifetime {
lifetimes: Box<[Name]>,
target: WherePredicateTypeTarget,
bound: Interned<TypeBound>,
},
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
Lifetime { target: LifetimeRef, bound: LifetimeRef },
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicateTypeTarget {
TypeRef(Interned<TypeRef>),
TypeRef(TypeRefId),
/// For desugared where predicates that can directly refer to a type param.
TypeOrConstParam(LocalTypeOrConstParamId),
}
@ -300,7 +297,14 @@ impl GenericParams {
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
) -> Arc<GenericParams> {
db.generic_params_with_source_map(def).0
}
pub(crate) fn generic_params_with_source_map_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db);
@ -309,7 +313,7 @@ impl GenericParams {
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
|params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@ -325,7 +329,7 @@ impl GenericParams {
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
Arc::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
@ -347,6 +351,7 @@ impl GenericParams {
.collect()
}),
where_predicates: params.where_predicates.clone(),
types_map: params.types_map.clone(),
})
}
};
@ -357,18 +362,18 @@ impl GenericParams {
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
&Interned<GenericParams>,
&Arc<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
) -> Arc<GenericParams>,
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(item.generic_params(), &tree, id.value.into())
(enabled_params(item.generic_params(), &tree, id.value.into()), None)
}
match def {
@ -383,28 +388,37 @@ impl GenericParams {
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
enabled_params
(enabled_params, None)
} else {
let source_maps = loc.id.item_tree_with_source_map(db).1;
let item_source_maps = source_maps.function(loc.id.value);
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
let (mut types_map, mut types_source_maps) =
(enabled_params.types_map.clone(), item_source_maps.generics().clone());
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = None;
for param in func_data.params.iter() {
for &param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(
db,
&mut types_map,
&mut types_source_maps,
&mut expander,
&mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
},
param,
&item.types_map,
item_source_maps.item(),
);
}
Interned::new(generic_params.finish())
let generics = generic_params.finish(types_map, &mut types_source_maps);
(generics, Some(Arc::new(types_source_maps)))
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@ -414,11 +428,15 @@ impl GenericParams {
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ConstId(_) => Interned::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
}),
GenericDefId::ConstId(_) => (
Arc::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
types_map: Default::default(),
}),
None,
),
}
}
}
@ -452,7 +470,7 @@ impl GenericParamsCollector {
&mut self,
lower_ctx: &LowerCtx<'_>,
type_bounds: Option<ast::TypeBoundList>,
target: Either<TypeRef, LifetimeRef>,
target: Either<TypeRefId, LifetimeRef>,
) {
for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
@ -473,16 +491,15 @@ impl GenericParamsCollector {
ast::TypeOrConstParam::Type(type_param) => {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src`
let default = type_param
.default_type()
.map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
let default =
type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
let param = TypeParamData {
name: Some(name.clone()),
default,
provenance: TypeParamProvenance::TypeParamList,
};
let idx = self.type_or_consts.alloc(param.into());
let type_ref = TypeRef::Path(name.into());
let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
self.fill_bounds(
lower_ctx,
type_param.type_bound_list(),
@ -492,12 +509,10 @@ impl GenericParamsCollector {
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
let ty = const_param
.ty()
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
let param = ConstParamData {
name,
ty: Interned::new(ty),
ty,
default: ConstRef::from_const_param(lower_ctx, &const_param),
};
let idx = self.type_or_consts.alloc(param.into());
@ -557,7 +572,7 @@ impl GenericParamsCollector {
lower_ctx: &LowerCtx<'_>,
bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>,
target: Either<TypeRef, LifetimeRef>,
target: Either<TypeRefId, LifetimeRef>,
) {
let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@ -565,12 +580,12 @@ impl GenericParamsCollector {
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
bound: Interned::new(bound),
target: WherePredicateTypeTarget::TypeRef(type_ref),
bound,
},
None => WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
bound: Interned::new(bound),
target: WherePredicateTypeTarget::TypeRef(type_ref),
bound,
},
},
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@ -581,7 +596,7 @@ impl GenericParamsCollector {
self.where_predicates.push(predicate);
}
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
for bounds in impl_bounds {
let param = TypeParamData {
name: None,
@ -589,10 +604,10 @@ impl GenericParamsCollector {
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
for bound in &bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound,
bound: bound.clone(),
});
}
}
@ -601,12 +616,16 @@ impl GenericParamsCollector {
fn fill_implicit_impl_trait_args(
&mut self,
db: &dyn DefDatabase,
generics_types_map: &mut TypesMap,
generics_types_source_map: &mut TypesSourceMap,
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
exp: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
type_ref: &TypeRef,
type_ref: TypeRefId,
types_map: &TypesMap,
types_source_map: &TypesSourceMap,
) {
type_ref.walk(&mut |type_ref| {
TypeRef::walk(type_ref, types_map, &mut |type_ref| {
if let TypeRef::ImplTrait(bounds) = type_ref {
let param = TypeParamData {
name: None,
@ -615,12 +634,20 @@ impl GenericParamsCollector {
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
let bound = copy_type_bound(
bound,
types_map,
types_source_map,
generics_types_map,
generics_types_source_map,
);
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound: bound.clone(),
bound,
});
}
}
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@ -641,23 +668,217 @@ impl GenericParamsCollector {
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
expander.enter_expand(db, macro_call, resolver)
{
let ctx = expander.ctx(db);
let (mut macro_types_map, mut macro_types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
self.fill_implicit_impl_trait_args(
db,
generics_types_map,
generics_types_source_map,
&mut *exp,
exp_fill,
type_ref,
&macro_types_map,
&macro_types_source_map,
);
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
}
}
});
}
pub(crate) fn finish(self) -> GenericParams {
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
pub(crate) fn finish(
self,
mut generics_types_map: TypesMap,
generics_types_source_map: &mut TypesSourceMap,
) -> Arc<GenericParams> {
let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
Arc::new(GenericParams {
lifetimes: Arena::new(),
type_or_consts: Arena::new(),
where_predicates: Box::default(),
types_map: TypesMap::default(),
})
});
return Arc::clone(&EMPTY);
}
lifetimes.shrink_to_fit();
type_or_consts.shrink_to_fit();
GenericParams {
where_predicates.shrink_to_fit();
generics_types_map.shrink_to_fit();
generics_types_source_map.shrink_to_fit();
Arc::new(GenericParams {
type_or_consts,
lifetimes,
where_predicates: where_predicates.into_boxed_slice(),
}
types_map: generics_types_map,
})
}
}
/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
/// (and `TypesSourceMap`).
fn copy_type_ref(
type_ref: TypeRefId,
from: &TypesMap,
from_source_map: &TypesSourceMap,
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> TypeRefId {
let result = match &from[type_ref] {
TypeRef::Fn(fn_) => {
let params = fn_.params().iter().map(|(name, param_type)| {
(name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
});
TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
}
TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
)),
&TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
mutbl,
),
TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
lifetime: ref_.lifetime.clone(),
mutability: ref_.mutability,
})),
TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
len: array.len.clone(),
})),
&TypeRef::Slice(type_ref) => {
TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
}
TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
bounds,
from,
from_source_map,
to,
to_source_map,
))),
TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
bounds,
from,
from_source_map,
to,
to_source_map,
))),
TypeRef::Path(path) => {
TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
}
TypeRef::Never => TypeRef::Never,
TypeRef::Placeholder => TypeRef::Placeholder,
TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
TypeRef::Error => TypeRef::Error,
};
let id = to.types.alloc(result);
if let Some(&ptr) = from_source_map.types_map_back.get(id) {
to_source_map.types_map_back.insert(id, ptr);
}
id
}
fn copy_path(
path: &Path,
from: &TypesMap,
from_source_map: &TypesSourceMap,
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> Path {
match path {
Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
Path::Normal(path) => {
let type_anchor = path
.type_anchor()
.map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
let mod_path = path.mod_path().clone();
let generic_args = path.generic_args().iter().map(|generic_args| {
copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
});
Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
}
Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
}
}
fn copy_generic_args(
generic_args: &Option<GenericArgs>,
from: &TypesMap,
from_source_map: &TypesSourceMap,
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> Option<GenericArgs> {
generic_args.as_ref().map(|generic_args| {
let args = generic_args
.args
.iter()
.map(|arg| match arg {
&GenericArg::Type(ty) => {
GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
}
GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
})
.collect();
let bindings = generic_args
.bindings
.iter()
.map(|binding| {
let name = binding.name.clone();
let args =
copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
let type_ref = binding.type_ref.map(|type_ref| {
copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
});
let bounds =
copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
.collect();
AssociatedTypeBinding { name, args, type_ref, bounds }
})
.collect();
GenericArgs {
args,
has_self_type: generic_args.has_self_type,
bindings,
desugared_from_fn: generic_args.desugared_from_fn,
}
})
}
fn copy_type_bounds<'a>(
bounds: &'a [TypeBound],
from: &'a TypesMap,
from_source_map: &'a TypesSourceMap,
to: &'a mut TypesMap,
to_source_map: &'a mut TypesSourceMap,
) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
}
fn copy_type_bound(
bound: &TypeBound,
from: &TypesMap,
from_source_map: &TypesSourceMap,
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> TypeBound {
match bound {
TypeBound::Path(path, modifier) => {
TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
}
TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
lifetimes.clone(),
copy_path(path, from, from_source_map, to, to_source_map),
),
TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
TypeBound::Error => TypeBound::Error,
}
}

View file

@ -17,16 +17,17 @@ pub mod type_ref;
use std::fmt;
use hir_expand::name::Name;
use intern::{Interned, Symbol};
use hir_expand::{name::Name, MacroDefId};
use intern::Symbol;
use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast;
use type_ref::TypeRefId;
use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
type_ref::{Mutability, Rawness},
BlockId, ConstBlockId,
};
@ -48,6 +49,22 @@ pub enum ExprOrPatId {
ExprId(ExprId),
PatId(PatId),
}
impl ExprOrPatId {
pub fn as_expr(self) -> Option<ExprId> {
match self {
Self::ExprId(v) => Some(v),
_ => None,
}
}
pub fn as_pat(self) -> Option<PatId> {
match self {
Self::PatId(v) => Some(v),
_ => None,
}
}
}
stdx::impl_from!(ExprId, PatId for ExprOrPatId);
#[derive(Debug, Clone, Eq, PartialEq)]
@ -204,7 +221,6 @@ pub enum Expr {
Call {
callee: ExprId,
args: Box<[ExprId]>,
is_assignee_expr: bool,
},
MethodCall {
receiver: ExprId,
@ -239,8 +255,6 @@ pub enum Expr {
path: Option<Box<Path>>,
fields: Box<[RecordLitField]>,
spread: Option<ExprId>,
ellipsis: bool,
is_assignee_expr: bool,
},
Field {
expr: ExprId,
@ -251,7 +265,7 @@ pub enum Expr {
},
Cast {
expr: ExprId,
type_ref: Interned<TypeRef>,
type_ref: TypeRefId,
},
Ref {
expr: ExprId,
@ -265,11 +279,17 @@ pub enum Expr {
expr: ExprId,
op: UnaryOp,
},
/// `op` cannot be bare `=` (but can be `op=`), these are lowered to `Assignment` instead.
BinaryOp {
lhs: ExprId,
rhs: ExprId,
op: Option<BinaryOp>,
},
// Assignments need a special treatment because of destructuring assignment.
Assignment {
target: PatId,
value: ExprId,
},
Range {
lhs: Option<ExprId>,
rhs: Option<ExprId>,
@ -278,19 +298,17 @@ pub enum Expr {
Index {
base: ExprId,
index: ExprId,
is_assignee_expr: bool,
},
Closure {
args: Box<[PatId]>,
arg_types: Box<[Option<Interned<TypeRef>>]>,
ret_type: Option<Interned<TypeRef>>,
arg_types: Box<[Option<TypeRefId>]>,
ret_type: Option<TypeRefId>,
body: ExprId,
closure_kind: ClosureKind,
capture_by: CaptureBy,
},
Tuple {
exprs: Box<[ExprId]>,
is_assignee_expr: bool,
},
Array(Array),
Literal(Literal),
@ -301,7 +319,7 @@ pub enum Expr {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetOf {
pub container: Interned<TypeRef>,
pub container: TypeRefId,
pub fields: Box<[Name]>,
}
@ -446,7 +464,7 @@ pub enum Movability {
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Array {
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
ElementList { elements: Box<[ExprId]> },
Repeat { initializer: ExprId, repeat: ExprId },
}
@ -467,7 +485,7 @@ pub struct RecordLitField {
pub enum Statement {
Let {
pat: PatId,
type_ref: Option<Interned<TypeRef>>,
type_ref: Option<TypeRefId>,
initializer: Option<ExprId>,
else_branch: Option<ExprId>,
},
@ -475,133 +493,13 @@ pub enum Statement {
expr: ExprId,
has_semi: bool,
},
// At the moment, we only use this to figure out if a return expression
// is really the last statement of a block. See #16566
Item,
Item(Item),
}
impl Expr {
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
match self {
Expr::Missing => {}
Expr::Path(_) | Expr::OffsetOf(_) => {}
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, .. }
| AsmOperand::Out { expr: Some(expr), .. }
| AsmOperand::InOut { expr, .. } => f(*expr),
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
f(*in_expr);
if let Some(out_expr) = out_expr {
f(*out_expr);
}
}
AsmOperand::Out { expr: None, .. }
| AsmOperand::Const(_)
| AsmOperand::Label(_)
| AsmOperand::Sym(_) => (),
}),
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
f(*then_branch);
if let &Some(else_branch) = else_branch {
f(else_branch);
}
}
Expr::Let { expr, .. } => {
f(*expr);
}
Expr::Const(_) => (),
Expr::Block { statements, tail, .. }
| Expr::Unsafe { statements, tail, .. }
| Expr::Async { statements, tail, .. } => {
for stmt in statements.iter() {
match stmt {
Statement::Let { initializer, else_branch, .. } => {
if let &Some(expr) = initializer {
f(expr);
}
if let &Some(expr) = else_branch {
f(expr);
}
}
Statement::Expr { expr: expression, .. } => f(*expression),
Statement::Item => (),
}
}
if let &Some(expr) = tail {
f(expr);
}
}
Expr::Loop { body, .. } => f(*body),
Expr::Call { callee, args, .. } => {
f(*callee);
args.iter().copied().for_each(f);
}
Expr::MethodCall { receiver, args, .. } => {
f(*receiver);
args.iter().copied().for_each(f);
}
Expr::Match { expr, arms } => {
f(*expr);
arms.iter().map(|arm| arm.expr).for_each(f);
}
Expr::Continue { .. } => {}
Expr::Break { expr, .. }
| Expr::Return { expr }
| Expr::Yield { expr }
| Expr::Yeet { expr } => {
if let &Some(expr) = expr {
f(expr);
}
}
Expr::Become { expr } => f(*expr),
Expr::RecordLit { fields, spread, .. } => {
for field in fields.iter() {
f(field.expr);
}
if let &Some(expr) = spread {
f(expr);
}
}
Expr::Closure { body, .. } => {
f(*body);
}
Expr::BinaryOp { lhs, rhs, .. } => {
f(*lhs);
f(*rhs);
}
Expr::Range { lhs, rhs, .. } => {
if let &Some(lhs) = rhs {
f(lhs);
}
if let &Some(rhs) = lhs {
f(rhs);
}
}
Expr::Index { base, index, .. } => {
f(*base);
f(*index);
}
Expr::Field { expr, .. }
| Expr::Await { expr }
| Expr::Cast { expr, .. }
| Expr::Ref { expr, .. }
| Expr::UnaryOp { expr, .. }
| Expr::Box { expr } => {
f(*expr);
}
Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
Expr::Array(a) => match a {
Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
Array::Repeat { initializer, repeat } => {
f(*initializer);
f(*repeat)
}
},
Expr::Literal(_) => {}
Expr::Underscore => {}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Item {
MacroDef(Box<MacroDefId>),
Other,
}
/// Explicit binding annotations given in the HIR for a binding. Note
@ -665,18 +563,49 @@ pub struct RecordFieldPat {
pub enum Pat {
Missing,
Wild,
Tuple { args: Box<[PatId]>, ellipsis: Option<u32> },
Tuple {
args: Box<[PatId]>,
ellipsis: Option<u32>,
},
Or(Box<[PatId]>),
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
Path(Box<Path>),
Record {
path: Option<Box<Path>>,
args: Box<[RecordFieldPat]>,
ellipsis: bool,
},
Range {
start: Option<Box<LiteralOrConst>>,
end: Option<Box<LiteralOrConst>>,
},
Slice {
prefix: Box<[PatId]>,
slice: Option<PatId>,
suffix: Box<[PatId]>,
},
/// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
Path(Path),
Lit(ExprId),
Bind { id: BindingId, subpat: Option<PatId> },
TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> },
Ref { pat: PatId, mutability: Mutability },
Box { inner: PatId },
Bind {
id: BindingId,
subpat: Option<PatId>,
},
TupleStruct {
path: Option<Box<Path>>,
args: Box<[PatId]>,
ellipsis: Option<u32>,
},
Ref {
pat: PatId,
mutability: Mutability,
},
Box {
inner: PatId,
},
ConstBlock(ExprId),
/// An expression inside a pattern. That can only occur inside assignments.
///
/// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression.
Expr(ExprId),
}
impl Pat {
@ -687,7 +616,8 @@ impl Pat {
| Pat::Path(..)
| Pat::ConstBlock(..)
| Pat::Wild
| Pat::Missing => {}
| Pat::Missing
| Pat::Expr(_) => {}
Pat::Bind { subpat, .. } => {
subpat.iter().copied().for_each(f);
}

View file

@ -2,22 +2,27 @@
//! be directly created from an ast::TypeRef, without further queries.
use core::fmt;
use std::fmt::Write;
use std::{fmt::Write, ops::Index};
use hir_expand::{
db::ExpandDatabase,
name::{AsName, Name},
AstId,
AstId, InFile,
};
use intern::{sym, Interned, Symbol};
use intern::{sym, Symbol};
use la_arena::{Arena, ArenaMap, Idx};
use span::Edition;
use syntax::ast::{self, HasGenericArgs, HasName, IsString};
use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
use syntax::{
ast::{self, HasGenericArgs, HasName, IsString},
AstPtr,
};
use crate::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
hir::Literal,
lower::LowerCtx,
path::Path,
path::{GenericArg, Path},
};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -104,35 +109,90 @@ impl TraitRef {
}
}
thin_vec_with_header_struct! {
pub new(pub(crate)) struct FnType, FnTypeHeader {
pub params: [(Option<Name>, TypeRefId)],
pub is_varargs: bool,
pub is_unsafe: bool,
pub abi: Option<Symbol>; ref,
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ArrayType {
pub ty: TypeRefId,
// FIXME: This should be Ast<ConstArg>
pub len: ConstRef,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct RefType {
pub ty: TypeRefId,
pub lifetime: Option<LifetimeRef>,
pub mutability: Mutability,
}
/// Compare ty::Ty
///
/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
/// does not seem to save any noticeable amount of memory.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Never,
Placeholder,
Tuple(Vec<TypeRef>),
Tuple(EmptyOptimizedThinVec<TypeRefId>),
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
Array(Box<TypeRef>, ConstRef),
Slice(Box<TypeRef>),
RawPtr(TypeRefId, Mutability),
Reference(Box<RefType>),
Array(Box<ArrayType>),
Slice(TypeRefId),
/// A fn pointer. Last element of the vector is the return type.
Fn(
Box<[(Option<Name>, TypeRef)]>,
bool, /*varargs*/
bool, /*is_unsafe*/
Option<Symbol>, /* abi */
),
ImplTrait(Vec<Interned<TypeBound>>),
DynTrait(Vec<Interned<TypeBound>>),
Fn(FnType),
ImplTrait(ThinVec<TypeBound>),
DynTrait(ThinVec<TypeBound>),
Macro(AstId<ast::MacroCall>),
Error,
}
#[cfg(target_arch = "x86_64")]
const _: () = assert!(size_of::<TypeRef>() == 16);
pub type TypeRefId = Idx<TypeRef>;
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypesMap {
pub(crate) types: Arena<TypeRef>,
}
impl TypesMap {
pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
pub(crate) fn shrink_to_fit(&mut self) {
let TypesMap { types } = self;
types.shrink_to_fit();
}
}
impl Index<TypeRefId> for TypesMap {
type Output = TypeRef;
fn index(&self, index: TypeRefId) -> &Self::Output {
&self.types[index]
}
}
pub type TypePtr = AstPtr<ast::Type>;
pub type TypeSource = InFile<TypePtr>;
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypesSourceMap {
pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
}
impl TypesSourceMap {
pub(crate) fn shrink_to_fit(&mut self) {
let TypesSourceMap { types_map_back } = self;
types_map_back.shrink_to_fit();
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct LifetimeRef {
pub name: Name,
@ -157,12 +217,22 @@ pub enum TypeBound {
Path(Path, TraitBoundModifier),
ForLifetime(Box<[Name]>, Path),
Lifetime(LifetimeRef),
Use(Box<[UseArgRef]>),
Error,
}
#[cfg(target_pointer_width = "64")]
const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum UseArgRef {
Name(Name),
Lifetime(LifetimeRef),
}
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TraitBoundModifier {
None,
Maybe,
@ -170,12 +240,12 @@ pub enum TraitBoundModifier {
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
match node {
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::TupleType(inner) => {
TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
}
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
let ty = match &node {
ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))),
)),
ast::Type::NeverType(..) => TypeRef::Never,
ast::Type::PathType(inner) => {
// FIXME: Use `Path::from_src`
@ -188,20 +258,21 @@ impl TypeRef {
ast::Type::PtrType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
TypeRef::RawPtr(Box::new(inner_ty), mutability)
TypeRef::RawPtr(inner_ty, mutability)
}
ast::Type::ArrayType(inner) => {
let len = ConstRef::from_const_arg(ctx, inner.const_arg());
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
TypeRef::Array(Box::new(ArrayType {
ty: TypeRef::from_ast_opt(ctx, inner.ty()),
len,
}))
}
ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
ast::Type::RefType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
}
ast::Type::InferType(_inner) => TypeRef::Placeholder,
ast::Type::FnPtrType(inner) => {
@ -209,7 +280,7 @@ impl TypeRef {
.ret_type()
.and_then(|rt| rt.ty())
.map(|it| TypeRef::from_ast(ctx, it))
.unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
.unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
let mut is_varargs = false;
let mut params = if let Some(pl) = inner.param_list() {
if let Some(param) = pl.params().last() {
@ -241,10 +312,10 @@ impl TypeRef {
let abi = inner.abi().map(lower_abi);
params.push((None, ret_ty));
TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
}
// for types are close enough for our purposes to the inner type for now...
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::ImplTraitType(inner) => {
if ctx.outer_impl_trait() {
// Disallow nested impl traits
@ -261,74 +332,74 @@ impl TypeRef {
Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
None => TypeRef::Error,
},
}
};
ctx.alloc_type_ref(ty, AstPtr::new(&node))
}
pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
match node {
Some(node) => TypeRef::from_ast(ctx, node),
None => TypeRef::Error,
None => ctx.alloc_error_type(),
}
}
pub(crate) fn unit() -> TypeRef {
TypeRef::Tuple(Vec::new())
TypeRef::Tuple(EmptyOptimizedThinVec::empty())
}
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
go(self, f);
pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
go(this, f, map);
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
let type_ref = &map[type_ref];
f(type_ref);
match type_ref {
TypeRef::Fn(params, _, _, _) => {
params.iter().for_each(|(_, param_type)| go(param_type, f))
TypeRef::Fn(fn_) => {
fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
}
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..)
| TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(type_ref, f),
TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
TypeRef::Reference(it) => go(it.ty, f, map),
TypeRef::Array(it) => go(it.ty, f, map),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
match bound.as_ref() {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
go_path(path, f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error => (),
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
}
}
TypeRef::Path(path) => go_path(path, f),
TypeRef::Path(path) => go_path(path, f, map),
TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
};
}
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
if let Some(type_ref) = path.type_anchor() {
go(type_ref, f);
go(type_ref, f, map);
}
for segment in path.segments().iter() {
if let Some(args_and_bindings) = segment.args_and_bindings {
for arg in args_and_bindings.args.iter() {
match arg {
crate::path::GenericArg::Type(type_ref) => {
go(type_ref, f);
GenericArg::Type(type_ref) => {
go(*type_ref, f, map);
}
crate::path::GenericArg::Const(_)
| crate::path::GenericArg::Lifetime(_) => {}
GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
}
}
for binding in args_and_bindings.bindings.iter() {
if let Some(type_ref) = &binding.type_ref {
go(type_ref, f);
if let Some(type_ref) = binding.type_ref {
go(type_ref, f, map);
}
for bound in binding.bounds.iter() {
match bound.as_ref() {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
go_path(path, f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error => (),
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
}
}
@ -341,11 +412,13 @@ impl TypeRef {
pub(crate) fn type_bounds_from_ast(
lower_ctx: &LowerCtx<'_>,
type_bounds_opt: Option<ast::TypeBoundList>,
) -> Vec<Interned<TypeBound>> {
) -> ThinVec<TypeBound> {
if let Some(type_bounds) = type_bounds_opt {
type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
ThinVec::from_iter(Vec::from_iter(
type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
))
} else {
vec![]
ThinVec::from_iter([])
}
}
@ -380,7 +453,16 @@ impl TypeBound {
None => TypeBound::Error,
}
}
ast::TypeBoundKind::Use(_) => TypeBound::Error,
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
gal.use_bound_generic_args()
.map(|p| match p {
ast::UseBoundGenericArg::Lifetime(l) => {
UseArgRef::Lifetime(LifetimeRef::new(&l))
}
ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
})
.collect(),
),
ast::TypeBoundKind::Lifetime(lifetime) => {
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
}
@ -391,7 +473,7 @@ impl TypeBound {
match self {
TypeBound::Path(p, m) => Some((p, m)),
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
TypeBound::Lifetime(_) | TypeBound::Error => None,
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
}
}
}

View file

@ -61,7 +61,7 @@ use crate::{
db::DefDatabase,
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};
@ -100,14 +100,20 @@ pub struct ItemTree {
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
db.file_item_tree_with_source_map(file_id).0
}
let syntax = db.parse_or_expand(file_id);
pub(crate) fn file_item_tree_with_source_map_query(
db: &dyn DefDatabase,
file_id: HirFileId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let ctx = lower::Ctx::new(db, file_id);
let syntax = db.parse_or_expand(file_id);
let mut top_attrs = None;
let mut item_tree = match_ast! {
let (mut item_tree, source_maps) = match_ast! {
match syntax {
ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@ -137,42 +143,55 @@ impl ItemTree {
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
(
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
}),
Arc::default(),
)
})
.clone()
} else {
item_tree.shrink_to_fit();
Arc::new(item_tree)
(Arc::new(item_tree), Arc::new(source_maps))
}
}
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
db.block_item_tree_with_source_map(block).0
}
pub(crate) fn block_item_tree_with_source_map_query(
db: &dyn DefDatabase,
block: BlockId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
let mut item_tree = ctx.lower_block(&block);
let (mut item_tree, source_maps) = ctx.lower_block(&block);
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
(
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
}),
Arc::default(),
)
})
.clone()
} else {
item_tree.shrink_to_fit();
Arc::new(item_tree)
(Arc::new(item_tree), Arc::new(source_maps))
}
}
@ -309,6 +328,160 @@ struct ItemTreeData {
vis: ItemVisibilities,
}
#[derive(Default, Debug, Eq, PartialEq)]
pub struct ItemTreeSourceMaps {
all_concatenated: Box<[TypesSourceMap]>,
structs_offset: u32,
unions_offset: u32,
enum_generics_offset: u32,
variants_offset: u32,
consts_offset: u32,
statics_offset: u32,
trait_generics_offset: u32,
trait_alias_generics_offset: u32,
impls_offset: u32,
type_aliases_offset: u32,
}
#[derive(Clone, Copy)]
pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
impl<'a> GenericItemSourceMap<'a> {
#[inline]
pub fn item(self) -> &'a TypesSourceMap {
&self.0[0]
}
#[inline]
pub fn generics(self) -> &'a TypesSourceMap {
&self.0[1]
}
}
#[derive(Default, Debug, Eq, PartialEq)]
pub struct GenericItemSourceMapBuilder {
pub item: TypesSourceMap,
pub generics: TypesSourceMap,
}
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeSourceMapsBuilder {
functions: Vec<GenericItemSourceMapBuilder>,
structs: Vec<GenericItemSourceMapBuilder>,
unions: Vec<GenericItemSourceMapBuilder>,
enum_generics: Vec<TypesSourceMap>,
variants: Vec<TypesSourceMap>,
consts: Vec<TypesSourceMap>,
statics: Vec<TypesSourceMap>,
trait_generics: Vec<TypesSourceMap>,
trait_alias_generics: Vec<TypesSourceMap>,
impls: Vec<GenericItemSourceMapBuilder>,
type_aliases: Vec<GenericItemSourceMapBuilder>,
}
impl ItemTreeSourceMapsBuilder {
fn build(self) -> ItemTreeSourceMaps {
let ItemTreeSourceMapsBuilder {
functions,
structs,
unions,
enum_generics,
variants,
consts,
statics,
trait_generics,
trait_alias_generics,
impls,
type_aliases,
} = self;
let structs_offset = functions.len() as u32 * 2;
let unions_offset = structs_offset + (structs.len() as u32 * 2);
let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
let consts_offset = variants_offset + (variants.len() as u32);
let statics_offset = consts_offset + (consts.len() as u32);
let trait_generics_offset = statics_offset + (statics.len() as u32);
let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
let all_concatenated = generics_concat(functions)
.chain(generics_concat(structs))
.chain(generics_concat(unions))
.chain(enum_generics)
.chain(variants)
.chain(consts)
.chain(statics)
.chain(trait_generics)
.chain(trait_alias_generics)
.chain(generics_concat(impls))
.chain(generics_concat(type_aliases))
.collect();
return ItemTreeSourceMaps {
all_concatenated,
structs_offset,
unions_offset,
enum_generics_offset,
variants_offset,
consts_offset,
statics_offset,
trait_generics_offset,
trait_alias_generics_offset,
impls_offset,
type_aliases_offset,
};
fn generics_concat(
source_maps: Vec<GenericItemSourceMapBuilder>,
) -> impl Iterator<Item = TypesSourceMap> {
source_maps.into_iter().flat_map(|it| [it.item, it.generics])
}
}
}
impl ItemTreeSourceMaps {
#[inline]
fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
GenericItemSourceMap(
self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
)
}
#[inline]
fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
&self.all_concatenated[(offset + index) as usize]
}
#[inline]
pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
self.generic_item(0, index.0.into_raw().into_u32())
}
}
macro_rules! index_item_source_maps {
( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
impl ItemTreeSourceMaps {
$(
#[inline]
pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
self.$fn(self.$field, index.0.into_raw().into_u32())
}
)*
}
};
}
index_item_source_maps! {
strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AttrOwner {
/// Attributes on an item.
@ -364,7 +537,7 @@ pub trait ItemTreeNode: Clone {
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
}
pub trait GenericsItemTreeNode: ItemTreeNode {
fn generic_params(&self) -> &Interned<GenericParams>;
fn generic_params(&self) -> &Arc<GenericParams>;
}
pub struct FileItemTreeId<N>(Idx<N>);
@ -429,6 +602,16 @@ impl TreeId {
}
}
pub fn item_tree_with_source_map(
&self,
db: &dyn DefDatabase,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
match self.block {
Some(block) => db.block_item_tree_with_source_map(block),
None => db.file_item_tree_with_source_map(self.file),
}
}
pub fn file_id(self) -> HirFileId {
self.file
}
@ -461,6 +644,13 @@ impl<N> ItemTreeId<N> {
self.tree.item_tree(db)
}
pub fn item_tree_with_source_map(
self,
db: &dyn DefDatabase,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
self.tree.item_tree_with_source_map(db)
}
pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
where
ItemTree: Index<FileItemTreeId<N>, Output = N>,
@ -593,7 +783,7 @@ macro_rules! mod_items {
$(
impl GenericsItemTreeNode for $typ {
fn generic_params(&self) -> &Interned<GenericParams> {
fn generic_params(&self) -> &Arc<GenericParams> {
&self.$generic_params
}
}
@ -731,17 +921,18 @@ pub struct ExternBlock {
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
pub explicit_generic_params: Interned<GenericParams>,
pub explicit_generic_params: Arc<GenericParams>,
pub abi: Option<Symbol>,
pub params: Box<[Param]>,
pub ret_type: Interned<TypeRef>,
pub ret_type: TypeRefId,
pub ast_id: FileAstId<ast::Fn>,
pub types_map: Arc<TypesMap>,
pub(crate) flags: FnFlags,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param {
pub type_ref: Option<Interned<TypeRef>>,
pub type_ref: Option<TypeRefId>,
}
bitflags::bitflags! {
@ -754,6 +945,7 @@ bitflags::bitflags! {
const HAS_ASYNC_KW = 1 << 4;
const HAS_UNSAFE_KW = 1 << 5;
const IS_VARARGS = 1 << 6;
const HAS_SAFE_KW = 1 << 7;
}
}
@ -761,26 +953,28 @@ bitflags::bitflags! {
pub struct Struct {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Struct>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Union {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub ast_id: FileAstId<ast::Union>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>,
}
@ -791,6 +985,7 @@ pub struct Variant {
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Variant>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -804,7 +999,7 @@ pub enum FieldsShape {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
}
@ -813,25 +1008,30 @@ pub struct Const {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Const>,
pub has_body: bool,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Static {
pub name: Name,
pub visibility: RawVisibilityId,
// TODO: use bitflags when we have more flags
pub mutable: bool,
pub type_ref: Interned<TypeRef>,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Static>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub is_auto: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
@ -842,19 +1042,20 @@ pub struct Trait {
pub struct TraitAlias {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub ast_id: FileAstId<ast::TraitAlias>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl {
pub generic_params: Interned<GenericParams>,
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
pub generic_params: Arc<GenericParams>,
pub target_trait: Option<TraitRef>,
pub self_ty: TypeRefId,
pub is_negative: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Impl>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -862,10 +1063,11 @@ pub struct TypeAlias {
pub name: Name,
pub visibility: RawVisibilityId,
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
pub bounds: Box<[Interned<TypeBound>]>,
pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>,
pub bounds: Box<[TypeBound]>,
pub generic_params: Arc<GenericParams>,
pub type_ref: Option<TypeRefId>,
pub ast_id: FileAstId<ast::TypeAlias>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@ -964,6 +1166,11 @@ impl UseTree {
self.expand_impl(None, &mut cb)
}
/// The [`UseTreeKind`] of this `UseTree`.
pub fn kind(&self) -> &UseTreeKind {
&self.kind
}
fn expand_impl(
&self,
prefix: Option<ModPath>,

View file

@ -1,12 +1,18 @@
//! AST -> `ItemTree` lowering code.
use std::collections::hash_map::Entry;
use std::{cell::OnceCell, collections::hash_map::Entry};
use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
use hir_expand::{
mod_path::path,
name::AsName,
span_map::{SpanMap, SpanMapRef},
HirFileId,
};
use intern::{sym, Symbol};
use la_arena::Arena;
use rustc_hash::FxHashMap;
use span::{AstIdMap, SyntaxContextId};
use stdx::thin_vec::ThinVec;
use syntax::{
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
AstNode,
@ -18,14 +24,19 @@ use crate::{
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
item_tree::{
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
Variant,
},
lower::LowerCtx,
path::AssociatedTypeBinding,
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
type_ref::{
LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
TypesMap, TypesSourceMap,
},
visibility::RawVisibility,
LocalLifetimeParamId, LocalTypeOrConstParamId,
};
@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> {
source_ast_id_map: Arc<AstIdMap>,
generic_param_attr_buffer:
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
body_ctx: crate::lower::LowerCtx<'a>,
span_map: OnceCell<SpanMap>,
file: HirFileId,
source_maps: ItemTreeSourceMapsBuilder,
}
impl<'a> Ctx<'a> {
@ -50,22 +63,49 @@ impl<'a> Ctx<'a> {
tree: ItemTree::default(),
generic_param_attr_buffer: FxHashMap::default(),
source_ast_id_map: db.ast_id_map(file),
body_ctx: crate::lower::LowerCtx::new(db, file),
file,
span_map: OnceCell::new(),
source_maps: ItemTreeSourceMapsBuilder::default(),
}
}
pub(super) fn span_map(&self) -> SpanMapRef<'_> {
self.body_ctx.span_map()
self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
}
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
fn body_ctx<'b, 'c>(
&self,
types_map: &'b mut TypesMap,
types_source_map: &'b mut TypesSourceMap,
) -> LowerCtx<'c>
where
'a: 'c,
'b: 'c,
{
// FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
LowerCtx::with_span_map_cell(
self.db,
self.file,
self.span_map.clone(),
types_map,
types_source_map,
)
}
pub(super) fn lower_module_items(
mut self,
item_owner: &dyn HasModuleItem,
) -> (ItemTree, ItemTreeSourceMaps) {
self.tree.top_level =
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
(self.tree, self.source_maps.build())
}
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
pub(super) fn lower_macro_stmts(
mut self,
stmts: ast::MacroStmts,
) -> (ItemTree, ItemTreeSourceMaps) {
self.tree.top_level = stmts
.statements()
.filter_map(|stmt| {
@ -96,10 +136,10 @@ impl<'a> Ctx<'a> {
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
(self.tree, self.source_maps.build())
}
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
self.tree
.attrs
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@ -125,7 +165,7 @@ impl<'a> Ctx<'a> {
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
(self.tree, self.source_maps.build())
}
fn data(&mut self) -> &mut ItemTreeData {
@ -144,7 +184,7 @@ impl<'a> Ctx<'a> {
ast::Item::Module(ast) => self.lower_module(ast)?.into(),
ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
ast::Item::Impl(ast) => self.lower_impl(ast).into(),
ast::Item::Use(ast) => self.lower_use(ast)?.into(),
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@ -159,12 +199,14 @@ impl<'a> Ctx<'a> {
}
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
match self.tree.attrs.entry(item) {
Entry::Occupied(mut entry) => {
*entry.get_mut() = entry.get().merge(attrs);
}
Entry::Vacant(entry) => {
entry.insert(attrs);
if !attrs.is_empty() {
match self.tree.attrs.entry(item) {
Entry::Occupied(mut entry) => {
*entry.get_mut() = entry.get().merge(attrs);
}
Entry::Vacant(entry) => {
entry.insert(attrs);
}
}
}
}
@ -190,13 +232,31 @@ impl<'a> Ctx<'a> {
}
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt);
let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, strukt);
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Struct {
name,
visibility,
generic_params,
fields,
shape: kind,
ast_id,
types_map: Arc::new(types_map),
};
let id = id(self.data().structs.alloc(res));
self.source_maps.structs.push(GenericItemSourceMapBuilder {
item: types_source_map,
generics: generics_source_map,
});
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@ -213,6 +273,7 @@ impl<'a> Ctx<'a> {
fn lower_fields(
&mut self,
strukt_kind: &ast::StructKind,
body_ctx: &LowerCtx<'_>,
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
match strukt_kind {
ast::StructKind::Record(it) => {
@ -220,7 +281,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
let data = self.lower_record_field(&field);
let data = self.lower_record_field(&field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@ -234,7 +295,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
let data = self.lower_tuple_field(i, &field);
let data = self.lower_tuple_field(i, &field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@ -247,35 +308,59 @@ impl<'a> Ctx<'a> {
}
}
fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
let name = match field.name() {
Some(name) => name.as_name(),
None => Name::missing(),
};
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
fn lower_tuple_field(
&mut self,
idx: usize,
field: &ast::TupleField,
body_ctx: &LowerCtx<'_>,
) -> Field {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(union);
let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union);
let (fields, _, attrs) = match union.record_field_list() {
Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
Some(record_field_list) => {
self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
}
None => (Box::default(), FieldsShape::Record, Vec::default()),
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
let res = Union { name, visibility, generic_params, fields, ast_id };
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, union);
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Union {
name,
visibility,
generic_params,
fields,
ast_id,
types_map: Arc::new(types_map),
};
let id = id(self.data().unions.alloc(res));
self.source_maps.unions.push(GenericItemSourceMapBuilder {
item: types_source_map,
generics: generics_source_map,
});
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@ -299,9 +384,11 @@ impl<'a> Ctx<'a> {
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
}
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, enum_);
let res = Enum { name, visibility, generic_params, variants, ast_id };
let id = id(self.data().enums.alloc(res));
self.source_maps.enum_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
@ -320,14 +407,20 @@ impl<'a> Ctx<'a> {
}
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = match variant.name() {
Some(name) => name.as_name(),
None => Name::missing(),
};
let (fields, kind, attrs) = self.lower_fields(&variant.kind());
let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(variant);
let res = Variant { name, fields, shape: kind, ast_id };
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
let id = self.data().variants.alloc(res);
self.source_maps.variants.push(types_source_map);
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@ -341,6 +434,10 @@ impl<'a> Ctx<'a> {
}
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(func);
let name = func.name()?.as_name();
@ -360,27 +457,31 @@ impl<'a> Ctx<'a> {
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
);
let self_type = match self_param.ty() {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
None => {
let self_type =
TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
Name::new_symbol_root(sym::Self_.clone()).into(),
));
match self_param.kind() {
ast::SelfParamKind::Owned => self_type,
ast::SelfParamKind::Ref => TypeRef::Reference(
Box::new(self_type),
self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Shared,
ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
TypeRef::Reference(Box::new(RefType {
ty: self_type,
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
mutability: Mutability::Shared,
})),
),
ast::SelfParamKind::MutRef => TypeRef::Reference(
Box::new(self_type),
self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Mut,
ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
TypeRef::Reference(Box::new(RefType {
ty: self_type,
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
mutability: Mutability::Mut,
})),
),
}
}
};
let type_ref = Interned::new(self_type);
params.push(Param { type_ref: Some(type_ref) });
params.push(Param { type_ref: Some(self_type) });
has_self_param = true;
}
for param in param_list.params() {
@ -391,9 +492,8 @@ impl<'a> Ctx<'a> {
Param { type_ref: None }
}
None => {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
let ty = Interned::new(type_ref);
Param { type_ref: Some(ty) }
let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
Param { type_ref: Some(type_ref) }
}
};
params.push(param);
@ -402,17 +502,17 @@ impl<'a> Ctx<'a> {
let ret_type = match func.ret_type() {
Some(rt) => match rt.ty() {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
None if rt.thin_arrow_token().is_some() => TypeRef::Error,
None => TypeRef::unit(),
Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
},
None => TypeRef::unit(),
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
};
let ret_type = if func.async_token().is_some() {
let future_impl = desugar_future_path(ret_type);
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
TypeRef::ImplTrait(vec![ty_bound])
let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
} else {
ret_type
};
@ -440,22 +540,34 @@ impl<'a> Ctx<'a> {
if func.unsafe_token().is_some() {
flags |= FnFlags::HAS_UNSAFE_KW;
}
if func.safe_token().is_some() {
flags |= FnFlags::HAS_SAFE_KW;
}
if has_var_args {
flags |= FnFlags::IS_VARARGS;
}
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, func);
let res = Function {
name,
visibility,
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
explicit_generic_params: generic_params,
abi,
params: params.into_boxed_slice(),
ret_type: Interned::new(ret_type),
ret_type,
ast_id,
types_map: Arc::new(types_map),
flags,
};
let id = id(self.data().functions.alloc(res));
self.source_maps.functions.push(GenericItemSourceMapBuilder {
item: types_source_map,
generics: generics_source_map,
});
for (idx, attr) in attrs {
self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
}
@ -467,34 +579,82 @@ impl<'a> Ctx<'a> {
&mut self,
type_alias: &ast::TypeAlias,
) -> Option<FileItemTreeId<TypeAlias>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = type_alias.name()?.as_name();
let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
let visibility = self.lower_visibility(type_alias);
let bounds = self.lower_type_bounds(type_alias);
let bounds = self.lower_type_bounds(type_alias, &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(type_alias);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, type_alias);
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = TypeAlias {
name,
visibility,
bounds,
generic_params,
type_ref,
ast_id,
types_map: Arc::new(types_map),
};
let id = id(self.data().type_aliases.alloc(res));
self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
item: types_source_map,
generics: generics_source_map,
});
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = static_.name()?.as_name();
let type_ref = self.lower_type_ref_opt(static_.ty());
let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
let visibility = self.lower_visibility(static_);
let mutable = static_.mut_token().is_some();
let has_safe_kw = static_.safe_token().is_some();
let has_unsafe_kw = static_.unsafe_token().is_some();
let ast_id = self.source_ast_id_map.ast_id(static_);
let res = Static { name, visibility, mutable, type_ref, ast_id };
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Static {
name,
visibility,
mutable,
type_ref,
ast_id,
has_safe_kw,
has_unsafe_kw,
types_map: Arc::new(types_map),
};
self.source_maps.statics.push(types_source_map);
Some(id(self.data().statics.alloc(res)))
}
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = konst.name().map(|it| it.as_name());
let type_ref = self.lower_type_ref_opt(konst.ty());
let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
let visibility = self.lower_visibility(konst);
let ast_id = self.source_ast_id_map.ast_id(konst);
let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Const {
name,
visibility,
type_ref,
ast_id,
has_body: konst.body().is_some(),
types_map: Arc::new(types_map),
};
self.source_maps.consts.push(types_source_map);
id(self.data().consts.alloc(res))
}
@ -533,10 +693,11 @@ impl<'a> Ctx<'a> {
.filter_map(|item_node| self.lower_assoc_item(&item_node))
.collect();
let generic_params =
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
let id = id(self.data().traits.alloc(def));
self.source_maps.trait_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
@ -548,24 +709,29 @@ impl<'a> Ctx<'a> {
let name = trait_alias_def.name()?.as_name();
let visibility = self.lower_visibility(trait_alias_def);
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
let generic_params = self.lower_generic_params(
let (generic_params, generics_source_map) = self.lower_generic_params(
HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
trait_alias_def,
);
let alias = TraitAlias { name, visibility, generic_params, ast_id };
let id = id(self.data().trait_aliases.alloc(alias));
self.source_maps.trait_alias_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let ast_id = self.source_ast_id_map.ast_id(impl_def);
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
// equals itself.
let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
let is_negative = impl_def.excl_token().is_some();
let is_unsafe = impl_def.unsafe_token().is_some();
@ -578,12 +744,27 @@ impl<'a> Ctx<'a> {
.collect();
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
let res =
Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, impl_def);
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Impl {
generic_params,
target_trait,
self_ty,
is_negative,
is_unsafe,
items,
ast_id,
types_map: Arc::new(types_map),
};
let id = id(self.data().impls.alloc(res));
self.source_maps.impls.push(GenericItemSourceMapBuilder {
item: types_source_map,
generics: generics_source_map,
});
self.write_generic_params_attributes(id.into());
Some(id)
id
}
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@ -686,14 +867,17 @@ impl<'a> Ctx<'a> {
&mut self,
has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams,
) -> Interned<GenericParams> {
) -> (Arc<GenericParams>, TypesSourceMap) {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| {
let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
let attrs = RawAttrs::new(self.db.upcast(), &param, body_ctx.span_map());
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
};
self.body_ctx.take_impl_traits_bounds();
body_ctx.take_impl_traits_bounds();
let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@ -709,23 +893,29 @@ impl<'a> Ctx<'a> {
// add super traits as bounds on Self
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
generics.fill_bounds(
&self.body_ctx,
&body_ctx,
bounds,
Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
Name::new_symbol_root(sym::Self_.clone()).into(),
))),
);
}
generics.fill(&self.body_ctx, node, add_param_attrs);
generics.fill(&body_ctx, node, add_param_attrs);
Interned::new(generics.finish())
let generics = generics.finish(types_map, &mut types_source_map);
(generics, types_source_map)
}
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
fn lower_type_bounds(
&mut self,
node: &dyn ast::HasTypeBounds,
body_ctx: &LowerCtx<'_>,
) -> Box<[TypeBound]> {
match node.type_bound_list() {
Some(bound_list) => bound_list
.bounds()
.map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
.collect(),
Some(bound_list) => {
bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
}
None => Box::default(),
}
}
@ -737,23 +927,6 @@ impl<'a> Ctx<'a> {
self.data().vis.alloc(vis)
}
fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
Some(Interned::new(trait_ref))
}
fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
Interned::new(tyref)
}
fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
match type_ref.map(|ty| self.lower_type_ref(&ty)) {
Some(it) => it,
None => Interned::new(TypeRef::Error),
}
}
fn next_variant_idx(&self) -> Idx<Variant> {
Idx::from_raw(RawIdx::from(
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@ -761,7 +934,7 @@ impl<'a> Ctx<'a> {
}
}
fn desugar_future_path(orig: TypeRef) -> Path {
fn desugar_future_path(orig: TypeRefId) -> Path {
let path = path![core::future::Future];
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
@ -771,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
type_ref: Some(orig),
bounds: Box::default(),
};
generic_args.push(Some(Interned::new(GenericArgs {
bindings: Box::new([binding]),
..GenericArgs::empty()
})));
generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
Path::from_known_path(path, generic_args)
}

View file

@ -10,11 +10,12 @@ use crate::{
item_tree::{
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
UseTree, UseTreeKind, Variant,
},
pretty::{print_path, print_type_bounds, print_type_ref},
type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
};
@ -121,7 +122,13 @@ impl Printer<'_> {
};
}
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
fn print_fields(
&mut self,
parent: FieldParent,
kind: FieldsShape,
fields: &[Field],
map: &TypesMap,
) {
let edition = self.edition;
match kind {
FieldsShape::Record => {
@ -135,7 +142,7 @@ impl Printer<'_> {
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@ -151,7 +158,7 @@ impl Printer<'_> {
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@ -167,20 +174,21 @@ impl Printer<'_> {
kind: FieldsShape,
fields: &[Field],
params: &GenericParams,
map: &TypesMap,
) {
match kind {
FieldsShape::Record => {
if self.print_where_clause(params) {
wln!(self);
}
self.print_fields(parent, kind, fields);
self.print_fields(parent, kind, fields, map);
}
FieldsShape::Unit => {
self.print_where_clause(params);
self.print_fields(parent, kind, fields);
self.print_fields(parent, kind, fields, map);
}
FieldsShape::Tuple => {
self.print_fields(parent, kind, fields);
self.print_fields(parent, kind, fields, map);
self.print_where_clause(params);
}
}
@ -262,6 +270,7 @@ impl Printer<'_> {
params,
ret_type,
ast_id,
types_map,
flags,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
@ -278,6 +287,9 @@ impl Printer<'_> {
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
w!(self, "unsafe ");
}
if flags.contains(FnFlags::HAS_SAFE_KW) {
w!(self, "safe ");
}
if let Some(abi) = abi {
w!(self, "extern \"{}\" ", abi);
}
@ -295,7 +307,7 @@ impl Printer<'_> {
w!(this, "self: ");
}
if let Some(type_ref) = type_ref {
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, types_map);
} else {
wln!(this, "...");
}
@ -304,7 +316,7 @@ impl Printer<'_> {
});
}
w!(self, ") -> ");
self.print_type_ref(ret_type);
self.print_type_ref(*ret_type, types_map);
self.print_where_clause(explicit_generic_params);
if flags.contains(FnFlags::HAS_BODY) {
wln!(self, " {{ ... }}");
@ -313,8 +325,15 @@ impl Printer<'_> {
}
}
ModItem::Struct(it) => {
let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
&self.tree[it];
let Struct {
visibility,
name,
fields,
shape: kind,
generic_params,
ast_id,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
@ -324,6 +343,7 @@ impl Printer<'_> {
*kind,
fields,
generic_params,
types_map,
);
if matches!(kind, FieldsShape::Record) {
wln!(self);
@ -332,7 +352,8 @@ impl Printer<'_> {
}
}
ModItem::Union(it) => {
let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
let Union { name, visibility, fields, generic_params, ast_id, types_map } =
&self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db.upcast(), self.edition));
@ -342,6 +363,7 @@ impl Printer<'_> {
FieldsShape::Record,
fields,
generic_params,
types_map,
);
wln!(self);
}
@ -355,18 +377,20 @@ impl Printer<'_> {
let edition = self.edition;
self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) {
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
let Variant { name, fields, shape: kind, ast_id, types_map } =
&this.tree[variant];
this.print_ast_id(ast_id.erase());
this.print_attrs_of(variant, "\n");
w!(this, "{}", name.display(self.db.upcast(), edition));
this.print_fields(FieldParent::Variant(variant), *kind, fields);
this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
wln!(this, ",");
}
});
wln!(self, "}}");
}
ModItem::Const(it) => {
let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
&self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "const ");
@ -375,19 +399,34 @@ impl Printer<'_> {
None => w!(self, "_"),
}
w!(self, ": ");
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, types_map);
wln!(self, " = _;");
}
ModItem::Static(it) => {
let Static { name, visibility, mutable, type_ref, ast_id } = &self.tree[it];
let Static {
name,
visibility,
mutable,
type_ref,
ast_id,
has_safe_kw,
has_unsafe_kw,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
if *has_safe_kw {
w!(self, "safe ");
}
if *has_unsafe_kw {
w!(self, "unsafe ");
}
w!(self, "static ");
if *mutable {
w!(self, "mut ");
}
w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, types_map);
w!(self, " = _;");
wln!(self);
}
@ -432,6 +471,7 @@ impl Printer<'_> {
items,
generic_params,
ast_id,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
if *is_unsafe {
@ -444,10 +484,10 @@ impl Printer<'_> {
w!(self, "!");
}
if let Some(tr) = target_trait {
self.print_path(&tr.path);
self.print_path(&tr.path, types_map);
w!(self, " for ");
}
self.print_type_ref(self_ty);
self.print_type_ref(*self_ty, types_map);
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for item in &**items {
@ -457,19 +497,26 @@ impl Printer<'_> {
wln!(self, "}}");
}
ModItem::TypeAlias(it) => {
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
&self.tree[it];
let TypeAlias {
name,
visibility,
bounds,
type_ref,
generic_params,
ast_id,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "type {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into());
if !bounds.is_empty() {
w!(self, ": ");
self.print_type_bounds(bounds);
self.print_type_bounds(bounds, types_map);
}
if let Some(ty) = type_ref {
w!(self, " = ");
self.print_type_ref(ty);
self.print_type_ref(*ty, types_map);
}
self.print_where_clause(generic_params);
w!(self, ";");
@ -526,19 +573,19 @@ impl Printer<'_> {
self.blank();
}
fn print_type_ref(&mut self, type_ref: &TypeRef) {
fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
let edition = self.edition;
print_type_ref(self.db, type_ref, self, edition).unwrap();
print_type_ref(self.db, type_ref, map, self, edition).unwrap();
}
fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
let edition = self.edition;
print_type_bounds(self.db, bounds, self, edition).unwrap();
print_type_bounds(self.db, bounds, map, self, edition).unwrap();
}
fn print_path(&mut self, path: &Path) {
fn print_path(&mut self, path: &Path, map: &TypesMap) {
let edition = self.edition;
print_path(self.db, path, self, edition).unwrap();
print_path(self.db, path, map, self, edition).unwrap();
}
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@ -569,7 +616,7 @@ impl Printer<'_> {
},
TypeOrConstParamData::ConstParamData(konst) => {
w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
self.print_type_ref(&konst.ty);
self.print_type_ref(konst.ty, &params.types_map);
}
}
}
@ -623,14 +670,16 @@ impl Printer<'_> {
};
match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeRef(ty) => {
this.print_type_ref(*ty, &params.types_map)
}
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
None => w!(this, "_anon_{}", id.into_raw()),
},
}
w!(this, ": ");
this.print_type_bounds(std::slice::from_ref(bound));
this.print_type_bounds(std::slice::from_ref(bound), &params.types_map);
}
});
true

View file

@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath,
}
intern::impl_internable!(
crate::type_ref::TypeRef,
crate::type_ref::TraitRef,
crate::type_ref::TypeBound,
crate::path::GenericArgs,
generics::GenericParams,
);

View file

@ -5,43 +5,53 @@ use hir_expand::{
span_map::{SpanMap, SpanMapRef},
AstId, HirFileId, InFile,
};
use intern::Interned;
use span::{AstIdMap, AstIdNode};
use stdx::thin_vec::ThinVec;
use syntax::ast;
use triomphe::Arc;
use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
use crate::{
db::DefDatabase,
path::Path,
type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
};
pub struct LowerCtx<'a> {
pub db: &'a dyn DefDatabase,
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
ast_id_map: OnceCell<Arc<AstIdMap>>,
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
// Prevent nested impl traits like `impl Foo<impl Bar>`.
outer_impl_trait: RefCell<bool>,
types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
}
pub(crate) struct OuterImplTraitGuard<'a> {
ctx: &'a LowerCtx<'a>,
pub(crate) struct OuterImplTraitGuard<'a, 'b> {
ctx: &'a LowerCtx<'b>,
old: bool,
}
impl<'a> OuterImplTraitGuard<'a> {
fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
let old = ctx.outer_impl_trait.replace(impl_trait);
Self { ctx, old }
}
}
impl<'a> Drop for OuterImplTraitGuard<'a> {
impl Drop for OuterImplTraitGuard<'_, '_> {
fn drop(&mut self) {
self.ctx.outer_impl_trait.replace(self.old);
}
}
impl<'a> LowerCtx<'a> {
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
pub fn new(
db: &'a dyn DefDatabase,
file_id: HirFileId,
types_map: &'a mut TypesMap,
types_source_map: &'a mut TypesSourceMap,
) -> Self {
LowerCtx {
db,
file_id,
@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
}
}
@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> {
db: &'a dyn DefDatabase,
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
types_map: &'a mut TypesMap,
types_source_map: &'a mut TypesSourceMap,
) -> Self {
LowerCtx {
db,
@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
}
}
@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> {
)
}
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
self.impl_trait_bounds.borrow_mut().push(bounds);
}
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
self.impl_trait_bounds.take()
}
@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> {
*self.outer_impl_trait.borrow()
}
pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
pub(crate) fn outer_impl_trait_scope<'b>(
&'b self,
impl_trait: bool,
) -> OuterImplTraitGuard<'b, 'a> {
OuterImplTraitGuard::new(self, impl_trait)
}
pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
let mut types_map = self.types_map.borrow_mut();
let (types_map, types_source_map) = &mut *types_map;
let id = types_map.types.alloc(type_ref);
types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
id
}
pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
self.types_map.borrow_mut().0.types.alloc(type_ref)
}
pub(crate) fn alloc_error_type(&self) -> TypeRefId {
self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
}
// FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
// to use proper mutability instead of interior mutability.
pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
}
}

View file

@ -122,7 +122,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
let mut expn_text = String::new();
if let Some(err) = exp.err {
format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0);
format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).message);
}
let (parse, token_map) = exp.value;
if expect_errors {

View file

@ -31,7 +31,7 @@ use crate::{
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
},
macro_call_as_call_id, macro_call_as_call_id_with_eager,
nameres::{
@ -985,12 +985,8 @@ impl DefCollector<'_> {
for (name, res) in resolutions {
match name {
Some(name) => {
changed |= self.push_res_and_update_glob_vis(
module_id,
name,
res.with_visibility(vis),
import,
);
changed |=
self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
}
None => {
let tr = match res.take_types() {
@ -1043,10 +1039,11 @@ impl DefCollector<'_> {
.collect::<Vec<_>>();
for (glob_importing_module, glob_import_vis, use_) in glob_imports {
let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
self.update_recursive(
glob_importing_module,
resolutions,
glob_import_vis,
vis,
Some(ImportType::Glob(use_)),
depth + 1,
);
@ -1058,8 +1055,44 @@ impl DefCollector<'_> {
module_id: LocalModuleId,
name: &Name,
mut defs: PerNs,
vis: Visibility,
def_import_type: Option<ImportType>,
) -> bool {
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
// or `pub use ::crate_name`.
//
// This has been historically allowed, but may be not allowed in future
// https://github.com/rust-lang/rust/issues/127909
if let Some((_, v, it)) = defs.types.as_mut() {
let is_extern_crate_reimport_without_prefix = || {
let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
return false;
};
let Some(ImportType::Import(id)) = def_import_type else {
return false;
};
let use_id = id.import.lookup(self.db).id;
let item_tree = use_id.item_tree(self.db);
let use_kind = item_tree[use_id.value].use_tree.kind();
let UseTreeKind::Single { path, .. } = use_kind else {
return false;
};
path.segments().len() < 2
};
if is_extern_crate_reimport_without_prefix() {
*v = vis;
} else {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
}
if let Some((_, v, _)) = defs.values.as_mut() {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
if let Some((_, v, _)) = defs.macros.as_mut() {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
let mut changed = false;
if let Some(ImportType::Glob(_)) = def_import_type {

View file

@ -10,6 +10,7 @@
//!
//! `ReachedFixedPoint` signals about this.
use either::Either;
use hir_expand::{name::Name, Lookup};
use span::Edition;
use triomphe::Arc;
@ -150,17 +151,8 @@ impl DefMap {
let mut arc;
let mut current_map = self;
loop {
let new = current_map.resolve_path_fp_with_macro_single(
db,
mode,
original_module,
path,
shadow,
expected_macro_subns,
);
// Merge `new` into `result`.
let mut merge = |new: ResolvePathResult| {
result.resolved_def = result.resolved_def.or(new.resolved_def);
if result.reached_fixedpoint == ReachedFixedPoint::No {
result.reached_fixedpoint = new.reached_fixedpoint;
@ -171,7 +163,9 @@ impl DefMap {
(Some(old), Some(new)) => Some(old.max(new)),
(None, new) => new,
};
};
loop {
match current_map.block {
Some(block) if original_module == Self::ROOT => {
// Block modules "inherit" names from its parent module.
@ -180,8 +174,38 @@ impl DefMap {
current_map = &arc;
}
// Proper (non-block) modules, including those in block `DefMap`s, don't.
_ => return result,
_ => {
if original_module != Self::ROOT && current_map.block.is_some() {
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
// the prelude items (which are not inserted into blocks because they can be overridden there).
original_module = Self::ROOT;
arc = db.crate_def_map(self.krate);
current_map = &arc;
let new = current_map.resolve_path_fp_in_all_preludes(
db,
mode,
original_module,
path,
shadow,
);
merge(new);
}
return result;
}
}
let new = current_map.resolve_path_fp_with_macro_single(
db,
mode,
original_module,
path,
shadow,
expected_macro_subns,
);
merge(new);
}
}
@ -195,7 +219,7 @@ impl DefMap {
expected_macro_subns: Option<MacroSubNs>,
) -> ResolvePathResult {
let mut segments = path.segments().iter().enumerate();
let mut curr_per_ns = match path.kind {
let curr_per_ns = match path.kind {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
cov_mark::hit!(macro_dollar_crate_self);
@ -296,25 +320,96 @@ impl DefMap {
PerNs::types(module.into(), Visibility::Public, None)
}
PathKind::Abs => {
// 2018-style absolute path -- only extern prelude
let segment = match segments.next() {
Some((_, segment)) => segment,
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
Either::Left(it) => it,
Either::Right(reached_fixed_point) => {
return ResolvePathResult::empty(reached_fixed_point)
}
},
};
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
}
/// Resolves a path only in the preludes, without accounting for item scopes.
pub(super) fn resolve_path_fp_in_all_preludes(
&self,
db: &dyn DefDatabase,
mode: ResolveMode,
original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> ResolvePathResult {
let mut segments = path.segments().iter().enumerate();
let curr_per_ns = match path.kind {
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
// FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
if self.data.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
{
let (_, segment) = match segments.next() {
Some((idx, segment)) => (idx, segment),
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(
def.into(),
Visibility::Public,
extern_crate.map(ImportOrExternCrate::ExternCrate),
)
} else {
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_extern_prelude(segment)
}
PathKind::Plain => {
let (_, segment) = match segments.next() {
Some((idx, segment)) => (idx, segment),
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
tracing::debug!("resolving {:?} in module", segment);
self.resolve_name_in_all_preludes(db, segment)
}
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
Either::Left(it) => it,
Either::Right(reached_fixed_point) => {
return ResolvePathResult::empty(reached_fixed_point)
}
},
PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
return ResolvePathResult::empty(ReachedFixedPoint::Yes)
}
};
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
}
/// 2018-style absolute path -- only extern prelude
fn resolve_path_abs<'a>(
&self,
segments: &mut impl Iterator<Item = (usize, &'a Name)>,
path: &ModPath,
) -> Either<PerNs, ReachedFixedPoint> {
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return Either::Right(ReachedFixedPoint::Yes),
};
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
Either::Left(PerNs::types(
def.into(),
Visibility::Public,
extern_crate.map(ImportOrExternCrate::ExternCrate),
))
} else {
Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
}
}
fn resolve_remaining_segments<'a>(
&self,
segments: impl Iterator<Item = (usize, &'a Name)>,
mut curr_per_ns: PerNs,
path: &ModPath,
db: &dyn DefDatabase,
shadow: BuiltinShadowMode,
original_module: LocalModuleId,
) -> ResolvePathResult {
for (i, segment) in segments {
let (curr, vis, imp) = match curr_per_ns.take_types_full() {
Some(r) => r,
@ -475,24 +570,9 @@ impl DefMap {
// they might been shadowed by local names.
return PerNs::none();
}
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
PerNs::types(
it.into(),
Visibility::Public,
extern_crate.map(ImportOrExternCrate::ExternCrate),
)
})
};
let macro_use_prelude = || {
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
PerNs::macros(
it,
Visibility::Public,
// FIXME?
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
)
})
self.resolve_name_in_extern_prelude(name)
};
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || {
if self.block.is_some() && module == DefMap::ROOT {
return PerNs::none();
@ -507,6 +587,38 @@ impl DefMap {
.or_else(prelude)
}
fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
// Resolve in:
// - extern prelude / macro_use prelude
// - std prelude
let extern_prelude = self.resolve_name_in_extern_prelude(name);
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || self.resolve_in_prelude(db, name);
extern_prelude.or_else(macro_use_prelude).or_else(prelude)
}
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
PerNs::types(
it.into(),
Visibility::Public,
extern_crate.map(ImportOrExternCrate::ExternCrate),
)
})
}
fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
PerNs::macros(
it,
Visibility::Public,
// FIXME?
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
)
})
}
fn resolve_name_in_crate_root_or_extern_prelude(
&self,
db: &dyn DefDatabase,
@ -525,16 +637,7 @@ impl DefMap {
// Don't resolve extern prelude in pseudo-module of a block.
return PerNs::none();
}
self.data.extern_prelude.get(name).copied().map_or(
PerNs::none(),
|(it, extern_crate)| {
PerNs::types(
it.into(),
Visibility::Public,
extern_crate.map(ImportOrExternCrate::ExternCrate),
)
},
)
self.resolve_name_in_extern_prelude(name)
};
from_crate_root.or_else(from_extern_prelude)

View file

@ -385,6 +385,52 @@ pub struct Arc;
);
}
#[test]
fn extern_crate_reexport() {
check(
r#"
//- /main.rs crate:main deps:importer
use importer::*;
use importer::extern_crate1::exported::*;
use importer::allowed_reexport::*;
use importer::extern_crate2::*;
use importer::not_allowed_reexport1;
use importer::not_allowed_reexport2;
//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
extern crate extern_crate1;
extern crate extern_crate2;
pub use extern_crate1;
pub use extern_crate1 as allowed_reexport;
pub use ::extern_crate;
pub use self::extern_crate as not_allowed_reexport1;
pub use crate::extern_crate as not_allowed_reexport2;
//- /extern_crate1.rs crate:extern_crate1
pub mod exported {
pub struct PublicItem;
struct PrivateItem;
}
pub struct Exported;
//- /extern_crate2.rs crate:extern_crate2
pub struct NotExported;
"#,
expect![[r#"
crate
Exported: t v
PublicItem: t v
allowed_reexport: t
exported: t
not_allowed_reexport1: _
not_allowed_reexport2: _
"#]],
);
}
#[test]
fn extern_crate_rename_2015_edition() {
check(

View file

@ -412,3 +412,42 @@ use reexport::*;
"#]],
);
}
#[test]
fn regression_18308() {
check(
r#"
use outer::*;
mod outer {
mod inner_superglob {
pub use super::*;
}
// The importing order matters!
pub use inner_superglob::*;
use super::glob_target::*;
}
mod glob_target {
pub struct ShouldBePrivate;
}
"#,
expect![[r#"
crate
glob_target: t
outer: t
crate::glob_target
ShouldBePrivate: t v
crate::outer
ShouldBePrivate: t v
inner_superglob: t
crate::outer::inner_superglob
ShouldBePrivate: t v
inner_superglob: t
"#]],
);
}

View file

@ -253,7 +253,8 @@ m!(Z);
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4);
});
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
let n_recalculated_item_trees =
events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_recalculated_item_trees, 6);
let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@ -308,7 +309,7 @@ pub type Ty = ();
let events = db.log_executed(|| {
db.file_item_tree(pos.file_id.into());
});
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_calculated_item_trees, 1);
let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
assert_eq!(n_parsed_files, 1);

View file

@ -9,11 +9,12 @@ use std::{
use crate::{
lang_item::LangItemTarget,
lower::LowerCtx,
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
};
use hir_expand::name::Name;
use intern::Interned;
use span::Edition;
use stdx::thin_vec::thin_vec_with_header_struct;
use syntax::ast;
pub use hir_expand::mod_path::{path, ModPath, PathKind};
@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Path {
/// A normal path
Normal {
/// Type based path like `<T>::foo`.
/// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
type_anchor: Option<Interned<TypeRef>>,
mod_path: Interned<ModPath>,
/// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
},
/// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
/// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
/// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
/// this is not a problem since many more paths have generics than a type anchor).
BarePath(Interned<ModPath>),
/// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
Normal(NormalPath),
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
/// links via a normal path since they might be private and not accessible in the usage place.
LangItem(LangItemTarget, Option<Name>),
}
// This type is being used a lot, make sure it doesn't grow unintentionally.
#[cfg(target_arch = "x86_64")]
const _: () = {
assert!(size_of::<Path>() == 16);
assert!(size_of::<Option<Path>>() == 16);
};
thin_vec_with_header_struct! {
pub new(pub(crate)) struct NormalPath, NormalPathHeader {
pub generic_args: [Option<GenericArgs>],
pub type_anchor: Option<TypeRefId>,
pub mod_path: Interned<ModPath>; ref,
}
}
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding {
pub name: Name,
/// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
/// would be `['a, T]`.
pub args: Option<Interned<GenericArgs>>,
pub args: Option<GenericArgs>,
/// The type bound to this associated type (in `Item = T`, this would be the
/// `T`). This can be `None` if there are bounds instead.
pub type_ref: Option<TypeRef>,
pub type_ref: Option<TypeRefId>,
/// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.)
pub bounds: Box<[Interned<TypeBound>]>,
pub bounds: Box<[TypeBound]>,
}
/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
Type(TypeRef),
Type(TypeRefId),
Lifetime(LifetimeRef),
Const(ConstRef),
}
@ -112,50 +126,49 @@ impl Path {
}
/// Converts a known mod path to `Path`.
pub fn from_known_path(
path: ModPath,
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
) -> Path {
let generic_args = generic_args.into();
assert_eq!(path.len(), generic_args.len());
Path::Normal {
type_anchor: None,
mod_path: Interned::new(path),
generic_args: Some(generic_args),
}
pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
}
/// Converts a known mod path to `Path`.
pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
Path::BarePath(Interned::new(path))
}
#[inline]
pub fn kind(&self) -> &PathKind {
match self {
Path::Normal { mod_path, .. } => &mod_path.kind,
Path::BarePath(mod_path) => &mod_path.kind,
Path::Normal(path) => &path.mod_path().kind,
Path::LangItem(..) => &PathKind::Abs,
}
}
pub fn type_anchor(&self) -> Option<&TypeRef> {
#[inline]
pub fn type_anchor(&self) -> Option<TypeRefId> {
match self {
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
Path::LangItem(..) => None,
Path::Normal(path) => path.type_anchor(),
Path::LangItem(..) | Path::BarePath(_) => None,
}
}
#[inline]
pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
match self {
Path::Normal(path) => Some(path.generic_args()),
Path::LangItem(..) | Path::BarePath(_) => None,
}
}
pub fn segments(&self) -> PathSegments<'_> {
match self {
Path::Normal { mod_path, generic_args, .. } => {
let s = PathSegments {
segments: mod_path.segments(),
generic_args: generic_args.as_deref(),
};
if let Some(generic_args) = s.generic_args {
assert_eq!(s.segments.len(), generic_args.len());
}
s
Path::BarePath(mod_path) => {
PathSegments { segments: mod_path.segments(), generic_args: None }
}
Path::Normal(path) => PathSegments {
segments: path.mod_path().segments(),
generic_args: Some(path.generic_args()),
},
Path::LangItem(_, seg) => PathSegments {
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
generic_args: None,
@ -165,34 +178,55 @@ impl Path {
pub fn mod_path(&self) -> Option<&ModPath> {
match self {
Path::Normal { mod_path, .. } => Some(mod_path),
Path::BarePath(mod_path) => Some(mod_path),
Path::Normal(path) => Some(path.mod_path()),
Path::LangItem(..) => None,
}
}
pub fn qualifier(&self) -> Option<Path> {
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
return None;
};
if mod_path.is_ident() {
return None;
match self {
Path::BarePath(mod_path) => {
if mod_path.is_ident() {
return None;
}
Some(Path::BarePath(Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
))))
}
Path::Normal(path) => {
let mod_path = path.mod_path();
if mod_path.is_ident() {
return None;
}
let type_anchor = path.type_anchor();
let generic_args = path.generic_args();
let qualifier_mod_path = Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
));
let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
Some(Path::Normal(NormalPath::new(
type_anchor,
qualifier_mod_path,
qualifier_generic_args.iter().cloned(),
)))
}
Path::LangItem(..) => None,
}
let res = Path::Normal {
type_anchor: type_anchor.clone(),
mod_path: Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
)),
generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
};
Some(res)
}
pub fn is_self_type(&self) -> bool {
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
return false;
};
type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
match self {
Path::BarePath(mod_path) => mod_path.is_Self(),
Path::Normal(path) => {
path.type_anchor().is_none()
&& path.mod_path().is_Self()
&& path.generic_args().iter().all(|args| args.is_none())
}
Path::LangItem(..) => false,
}
}
}
@ -204,7 +238,7 @@ pub struct PathSegment<'a> {
pub struct PathSegments<'a> {
segments: &'a [Name],
generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
generic_args: Option<&'a [Option<GenericArgs>]>,
}
impl<'a> PathSegments<'a> {
@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> {
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
let res = PathSegment {
name: self.segments.get(idx)?,
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
};
Some(res)
}
@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> {
self.segments
.iter()
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
}
}
@ -268,16 +302,6 @@ impl GenericArgs {
impl From<Name> for Path {
fn from(name: Name) -> Path {
Path::Normal {
type_anchor: None,
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
generic_args: None,
}
}
}
impl From<Name> for Box<Path> {
fn from(name: Name) -> Box<Path> {
Box::new(Path::from(name))
Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
}
}

View file

@ -2,13 +2,14 @@
use std::iter;
use crate::{lower::LowerCtx, type_ref::ConstRef};
use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
use hir_expand::{
mod_path::resolve_crate_root,
name::{AsName, Name},
};
use intern::{sym, Interned};
use stdx::thin_vec::EmptyOptimizedThinVec;
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
use crate::{
@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
segment.param_list(),
segment.ret_type(),
)
})
.map(Interned::new);
});
if args.is_some() {
generic_args.resize(segments.len(), None);
generic_args.push(args);
@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
match trait_ref {
// <T>::foo
None => {
type_anchor = Some(Interned::new(self_type));
type_anchor = Some(self_type);
kind = PathKind::Plain;
}
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
Some(trait_ref) => {
let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
Path::from_src(ctx, trait_ref.path()?)?
else {
return None;
};
let path = Path::from_src(ctx, trait_ref.path()?)?;
let mod_path = path.mod_path()?;
let path_generic_args = path.generic_args();
let num_segments = mod_path.segments().len();
kind = mod_path.kind;
@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
// Insert the type reference (T in the above example) as Self parameter for the trait
let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
*last_segment = Some(Interned::new(match last_segment.take() {
*last_segment = Some(match last_segment.take() {
Some(it) => GenericArgs {
args: iter::once(self_type)
.chain(it.args.iter().cloned())
@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
has_self_type: true,
..GenericArgs::empty()
},
}));
});
}
}
}
@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
};
}
segments.reverse();
if !generic_args.is_empty() {
if !generic_args.is_empty() || type_anchor.is_some() {
generic_args.resize(segments.len(), None);
generic_args.reverse();
}
@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
}
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
return Some(Path::Normal {
type_anchor,
mod_path,
generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
});
if type_anchor.is_none() && generic_args.is_empty() {
return Some(Path::BarePath(mod_path));
} else {
return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
}
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() {
@ -194,11 +192,13 @@ pub(super) fn lower_generic_args(
match generic_arg {
ast::GenericArg::TypeArg(type_arg) => {
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
type_ref.walk(&mut |tr| {
let types_map = lower_ctx.types_map();
TypeRef::walk(type_ref, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
drop(types_map);
args.push(GenericArg::Type(type_ref));
}
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@ -212,20 +212,19 @@ pub(super) fn lower_generic_args(
let name = name_ref.as_name();
let args = assoc_type_arg
.generic_arg_list()
.and_then(|args| lower_generic_args(lower_ctx, args))
.map(Interned::new);
.and_then(|args| lower_generic_args(lower_ctx, args));
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
let type_ref = type_ref.inspect(|tr| {
tr.walk(&mut |tr| {
let type_ref = type_ref.inspect(|&tr| {
let types_map = lower_ctx.types_map();
TypeRef::walk(tr, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
drop(types_map);
});
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
l.bounds()
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
.collect()
l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
} else {
Box::default()
};
@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path(
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref);
}
let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
let args = Box::new([GenericArg::Type(
ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))),
)]);
let bindings = if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
Box::new([AssociatedTypeBinding {
@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
}])
} else {
// -> ()
let type_ref = TypeRef::Tuple(Vec::new());
let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
Box::new([AssociatedTypeBinding {
name: Name::new_symbol_root(sym::Output.clone()),
args: None,

View file

@ -1,9 +1,11 @@
//! Display and pretty printing routines.
use std::fmt::{self, Write};
use std::{
fmt::{self, Write},
mem,
};
use hir_expand::mod_path::PathKind;
use intern::Interned;
use itertools::Itertools;
use span::Edition;
@ -11,12 +13,15 @@ use crate::{
db::DefDatabase,
lang_item::LangItemTarget,
path::{GenericArg, GenericArgs, Path},
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
type_ref::{
Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
},
};
pub(crate) fn print_path(
db: &dyn DefDatabase,
path: &Path,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@ -58,7 +63,7 @@ pub(crate) fn print_path(
match path.type_anchor() {
Some(anchor) => {
write!(buf, "<")?;
print_type_ref(db, anchor, buf, edition)?;
print_type_ref(db, anchor, map, buf, edition)?;
write!(buf, ">::")?;
}
None => match path.kind() {
@ -87,7 +92,7 @@ pub(crate) fn print_path(
write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
if let Some(generics) = segment.args_and_bindings {
write!(buf, "::<")?;
print_generic_args(db, generics, buf, edition)?;
print_generic_args(db, generics, map, buf, edition)?;
write!(buf, ">")?;
}
@ -99,6 +104,7 @@ pub(crate) fn print_path(
pub(crate) fn print_generic_args(
db: &dyn DefDatabase,
generics: &GenericArgs,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@ -106,7 +112,7 @@ pub(crate) fn print_generic_args(
let args = if generics.has_self_type {
let (self_ty, args) = generics.args.split_first().unwrap();
write!(buf, "Self=")?;
print_generic_arg(db, self_ty, buf, edition)?;
print_generic_arg(db, self_ty, map, buf, edition)?;
first = false;
args
} else {
@ -117,7 +123,7 @@ pub(crate) fn print_generic_args(
write!(buf, ", ")?;
}
first = false;
print_generic_arg(db, arg, buf, edition)?;
print_generic_arg(db, arg, map, buf, edition)?;
}
for binding in generics.bindings.iter() {
if !first {
@ -127,11 +133,11 @@ pub(crate) fn print_generic_args(
write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
if !binding.bounds.is_empty() {
write!(buf, ": ")?;
print_type_bounds(db, &binding.bounds, buf, edition)?;
print_type_bounds(db, &binding.bounds, map, buf, edition)?;
}
if let Some(ty) = &binding.type_ref {
if let Some(ty) = binding.type_ref {
write!(buf, " = ")?;
print_type_ref(db, ty, buf, edition)?;
print_type_ref(db, ty, map, buf, edition)?;
}
}
Ok(())
@ -140,11 +146,12 @@ pub(crate) fn print_generic_args(
pub(crate) fn print_generic_arg(
db: &dyn DefDatabase,
arg: &GenericArg,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
match arg {
GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
}
@ -152,12 +159,13 @@ pub(crate) fn print_generic_arg(
pub(crate) fn print_type_ref(
db: &dyn DefDatabase,
type_ref: &TypeRef,
type_ref: TypeRefId,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
// FIXME: deduplicate with `HirDisplay` impl
match type_ref {
match &map[type_ref] {
TypeRef::Never => write!(buf, "!")?,
TypeRef::Placeholder => write!(buf, "_")?,
TypeRef::Tuple(fields) => {
@ -166,48 +174,48 @@ pub(crate) fn print_type_ref(
if i != 0 {
write!(buf, ", ")?;
}
print_type_ref(db, field, buf, edition)?;
print_type_ref(db, *field, map, buf, edition)?;
}
write!(buf, ")")?;
}
TypeRef::Path(path) => print_path(db, path, buf, edition)?,
TypeRef::Path(path) => print_path(db, path, map, buf, edition)?,
TypeRef::RawPtr(pointee, mtbl) => {
let mtbl = match mtbl {
Mutability::Shared => "*const",
Mutability::Mut => "*mut",
};
write!(buf, "{mtbl} ")?;
print_type_ref(db, pointee, buf, edition)?;
print_type_ref(db, *pointee, map, buf, edition)?;
}
TypeRef::Reference(pointee, lt, mtbl) => {
let mtbl = match mtbl {
TypeRef::Reference(ref_) => {
let mtbl = match ref_.mutability {
Mutability::Shared => "",
Mutability::Mut => "mut ",
};
write!(buf, "&")?;
if let Some(lt) = lt {
if let Some(lt) = &ref_.lifetime {
write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
}
write!(buf, "{mtbl}")?;
print_type_ref(db, pointee, buf, edition)?;
print_type_ref(db, ref_.ty, map, buf, edition)?;
}
TypeRef::Array(elem, len) => {
TypeRef::Array(array) => {
write!(buf, "[")?;
print_type_ref(db, elem, buf, edition)?;
write!(buf, "; {}]", len.display(db.upcast(), edition))?;
print_type_ref(db, array.ty, map, buf, edition)?;
write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
}
TypeRef::Slice(elem) => {
write!(buf, "[")?;
print_type_ref(db, elem, buf, edition)?;
print_type_ref(db, *elem, map, buf, edition)?;
write!(buf, "]")?;
}
TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
TypeRef::Fn(fn_) => {
let ((_, return_type), args) =
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
if *is_unsafe {
fn_.params().split_last().expect("TypeRef::Fn is missing return type");
if fn_.is_unsafe() {
write!(buf, "unsafe ")?;
}
if let Some(abi) = abi {
if let Some(abi) = fn_.abi() {
buf.write_str("extern ")?;
buf.write_str(abi.as_str())?;
buf.write_char(' ')?;
@ -217,16 +225,16 @@ pub(crate) fn print_type_ref(
if i != 0 {
write!(buf, ", ")?;
}
print_type_ref(db, typeref, buf, edition)?;
print_type_ref(db, *typeref, map, buf, edition)?;
}
if *varargs {
if fn_.is_varargs() {
if !args.is_empty() {
write!(buf, ", ")?;
}
write!(buf, "...")?;
}
write!(buf, ") -> ")?;
print_type_ref(db, return_type, buf, edition)?;
print_type_ref(db, *return_type, map, buf, edition)?;
}
TypeRef::Macro(_ast_id) => {
write!(buf, "<macro>")?;
@ -234,11 +242,11 @@ pub(crate) fn print_type_ref(
TypeRef::Error => write!(buf, "{{unknown}}")?,
TypeRef::ImplTrait(bounds) => {
write!(buf, "impl ")?;
print_type_bounds(db, bounds, buf, edition)?;
print_type_bounds(db, bounds, map, buf, edition)?;
}
TypeRef::DynTrait(bounds) => {
write!(buf, "dyn ")?;
print_type_bounds(db, bounds, buf, edition)?;
print_type_bounds(db, bounds, map, buf, edition)?;
}
}
@ -247,7 +255,8 @@ pub(crate) fn print_type_ref(
pub(crate) fn print_type_bounds(
db: &dyn DefDatabase,
bounds: &[Interned<TypeBound>],
bounds: &[TypeBound],
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@ -256,13 +265,13 @@ pub(crate) fn print_type_bounds(
write!(buf, " + ")?;
}
match bound.as_ref() {
match bound {
TypeBound::Path(path, modifier) => {
match modifier {
TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(buf, "?")?,
}
print_path(db, path, buf, edition)?;
print_path(db, path, map, buf, edition)?;
}
TypeBound::ForLifetime(lifetimes, path) => {
write!(
@ -270,9 +279,25 @@ pub(crate) fn print_type_bounds(
"for<{}> ",
lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
)?;
print_path(db, path, buf, edition)?;
print_path(db, path, map, buf, edition)?;
}
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
TypeBound::Use(args) => {
write!(buf, "use<")?;
let mut first = true;
for arg in args {
if !mem::take(&mut first) {
write!(buf, ", ")?;
}
match arg {
UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
UseArgRef::Lifetime(it) => {
write!(buf, "{}", it.name.display(db.upcast(), edition))?
}
}
}
write!(buf, ">")?
}
TypeBound::Error => write!(buf, "{{unknown}}")?,
}
}

View file

@ -3,14 +3,17 @@ use std::{fmt, iter, mem};
use base_db::CrateId;
use hir_expand::{name::Name, MacroDefId};
use intern::{sym, Interned};
use intern::sym;
use itertools::Itertools as _;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
use triomphe::Arc;
use crate::{
body::scope::{ExprScopes, ScopeId},
body::{
scope::{ExprScopes, ScopeId},
HygieneId,
},
builtin_type::BuiltinType,
data::ExternCrateDeclData,
db::DefDatabase,
@ -21,7 +24,7 @@ use crate::{
nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
type_ref::LifetimeRef,
type_ref::{LifetimeRef, TypesMap},
visibility::{RawVisibility, Visibility},
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@ -73,13 +76,15 @@ enum Scope {
/// All the items and imported names of a module
BlockScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope
GenericParams { def: GenericDefId, params: Interned<GenericParams> },
GenericParams { def: GenericDefId, params: Arc<GenericParams> },
/// Brings `Self` in `impl` block into scope
ImplDefScope(ImplId),
/// Brings `Self` in enum, struct and union definitions into scope
AdtScope(AdtId),
/// Local bindings
ExprScope(ExprScope),
/// Macro definition inside bodies that affects all paths after it in the same block.
MacroDefScope(Box<MacroDefId>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -162,7 +167,8 @@ impl Resolver {
path: &Path,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(),
Path::LangItem(l, seg) => {
let type_ns = match *l {
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
@ -188,7 +194,7 @@ impl Resolver {
for scope in self.scopes() {
match scope {
Scope::ExprScope(_) => continue,
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
return Some((TypeNs::GenericParam(id), remaining_idx(), None));
@ -257,9 +263,11 @@ impl Resolver {
&self,
db: &dyn DefDatabase,
path: &Path,
mut hygiene_id: HygieneId,
) -> Option<ResolveValueResult> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(),
Path::LangItem(l, None) => {
return Some(ResolveValueResult::ValueNs(
match *l {
@ -300,14 +308,22 @@ impl Resolver {
}
if n_segments <= 1 {
let mut hygiene_info = if !hygiene_id.is_root() {
let ctx = db.lookup_intern_syntax_context(hygiene_id.0);
ctx.outer_expn.map(|expansion| {
let expansion = db.lookup_intern_macro_call(expansion);
(ctx.parent, expansion.def)
})
} else {
None
};
for scope in self.scopes() {
match scope {
Scope::ExprScope(scope) => {
let entry = scope
.expr_scopes
.entries(scope.scope_id)
.iter()
.find(|entry| entry.name() == first_name);
let entry =
scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| {
entry.name() == first_name && entry.hygiene() == hygiene_id
});
if let Some(e) = entry {
return Some(ResolveValueResult::ValueNs(
@ -316,6 +332,21 @@ impl Resolver {
));
}
}
Scope::MacroDefScope(macro_id) => {
if let Some((parent_ctx, label_macro_id)) = hygiene_info {
if label_macro_id == **macro_id {
// A macro is allowed to refer to variables from before its declaration.
// Therefore, if we got to the rib of its declaration, give up its hygiene
// and use its parent expansion.
let parent_ctx = db.lookup_intern_syntax_context(parent_ctx);
hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
hygiene_info = parent_ctx.outer_expn.map(|expansion| {
let expansion = db.lookup_intern_macro_call(expansion);
(parent_ctx.parent, expansion.def)
});
}
}
}
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam(id);
@ -342,7 +373,7 @@ impl Resolver {
} else {
for scope in self.scopes() {
match scope {
Scope::ExprScope(_) => continue,
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam(id);
@ -393,8 +424,9 @@ impl Resolver {
&self,
db: &dyn DefDatabase,
path: &Path,
hygiene: HygieneId,
) -> Option<ValueNs> {
match self.resolve_path_in_value_ns(db, path)? {
match self.resolve_path_in_value_ns(db, path, hygiene)? {
ResolveValueResult::ValueNs(it, _) => Some(it),
ResolveValueResult::Partial(..) => None,
}
@ -590,13 +622,15 @@ impl Resolver {
pub fn where_predicates_in_scope(
&self,
) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
self.scopes()
.filter_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((params, def)),
_ => None,
})
.flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def)))
.flat_map(|(params, def)| {
params.where_predicates().zip(iter::repeat((def, &params.types_map)))
})
}
pub fn generic_def(&self) -> Option<GenericDefId> {
@ -606,13 +640,20 @@ impl Resolver {
})
}
pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
pub fn generic_params(&self) -> Option<&Arc<GenericParams>> {
self.scopes().find_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
_ => None,
})
}
pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> {
self.scopes().filter_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((&**params, def)),
_ => None,
})
}
pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner),
@ -622,7 +663,7 @@ impl Resolver {
pub fn type_owner(&self) -> Option<TypeOwnerId> {
self.scopes().find_map(|scope| match scope {
Scope::BlockScope(_) => None,
Scope::BlockScope(_) | Scope::MacroDefScope(_) => None,
&Scope::GenericParams { def, .. } => Some(def.into()),
&Scope::ImplDefScope(id) => Some(id.into()),
&Scope::AdtScope(adt) => Some(adt.into()),
@ -653,6 +694,9 @@ impl Resolver {
expr_scopes: &Arc<ExprScopes>,
scope_id: ScopeId,
) {
if let Some(macro_id) = expr_scopes.macro_def(scope_id) {
resolver.scopes.push(Scope::MacroDefScope(macro_id.clone()));
}
resolver.scopes.push(Scope::ExprScope(ExprScope {
owner,
expr_scopes: expr_scopes.clone(),
@ -670,7 +714,7 @@ impl Resolver {
}
let start = self.scopes.len();
let innermost_scope = self.scopes().next();
let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_)));
match innermost_scope {
Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => {
let expr_scopes = expr_scopes.clone();
@ -794,6 +838,7 @@ impl Scope {
acc.add_local(e.name(), e.binding());
});
}
Scope::MacroDefScope(_) => {}
}
}
}
@ -833,6 +878,9 @@ fn resolver_for_scope_(
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
}
if let Some(macro_id) = scopes.macro_def(scope) {
r = r.push_scope(Scope::MacroDefScope(macro_id.clone()));
}
r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
}
@ -1006,12 +1054,12 @@ impl HasResolver for ModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
let mut def_map = self.def_map(db);
let mut module_id = self.local_id;
let mut modules: SmallVec<[_; 1]> = smallvec![];
if !self.is_block_module() {
return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, module_id } };
}
let mut modules: SmallVec<[_; 1]> = smallvec![];
while let Some(parent) = def_map.parent() {
let block_def_map = mem::replace(&mut def_map, parent.def_map(db));
modules.push(block_def_map);

View file

@ -198,7 +198,10 @@ impl TestDB {
.filter_map(|node| {
let block = ast::BlockExpr::cast(node)?;
let expr = ast::Expr::from(block);
let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?;
let expr_id = source_map
.node_expr(InFile::new(position.file_id.into(), &expr))?
.as_expr()
.unwrap();
let scope = scopes.scope_for(expr_id).unwrap();
Some(scope)
});

View file

@ -139,13 +139,11 @@ impl Visibility {
let def_map_block = def_map.block_id();
loop {
match (to_module.block, def_map_block) {
// to_module is not a block, so there is no parent def map to use
// `to_module` is not a block, so there is no parent def map to use.
(None, _) => (),
// `to_module` is at `def_map`'s block, no need to move further.
(Some(a), Some(b)) if a == b => {
cov_mark::hit!(is_visible_from_same_block_def_map);
if let Some(parent) = def_map.parent() {
to_module = parent;
}
}
_ => {
if let Some(parent) = to_module.def_map(db).parent() {
@ -193,6 +191,11 @@ impl Visibility {
return None;
}
let def_block = def_map.block_id();
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
return None;
}
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
@ -212,6 +215,43 @@ impl Visibility {
}
}
}
/// Returns the least permissive visibility of `self` and `other`.
///
/// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
/// visible in unrelated modules).
pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
(vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
if mod_a.krate != mod_b.krate {
return None;
}
let def_block = def_map.block_id();
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
return None;
}
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A
return Some(Visibility::Module(mod_a, expl_b));
}
if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_b, expl_a));
}
None
}
}
}
}
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without

View file

@ -26,6 +26,7 @@ use crate::{
/// Syntactical attributes, without filtering of `cfg_attr`s.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RawAttrs {
// FIXME: This can become `Box<[Attr]>` if https://internals.rust-lang.org/t/layout-of-dst-box/21728?u=chrefr is accepted.
entries: Option<ThinArc<(), Attr>>,
}
@ -169,6 +170,10 @@ impl RawAttrs {
};
RawAttrs { entries }
}
pub fn is_empty(&self) -> bool {
self.entries.is_none()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -5,19 +5,20 @@ use cfg::CfgExpr;
use either::Either;
use intern::{sym, Symbol};
use mbe::{expect_fragment, DelimiterKind};
use span::{Edition, EditionedFileId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use span::{Edition, EditionedFileId, Span};
use stdx::format_to;
use syntax::{
format_smolstr,
unescape::{unescape_byte, unescape_char, unescape_unicode, Mode},
};
use syntax_bridge::parse_to_token_tree;
use syntax_bridge::syntax_node_to_token_tree;
use crate::{
builtin::quote::{dollar_crate, quote},
db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name,
span_map::SpanMap,
tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId,
};
@ -739,18 +740,14 @@ fn include_expand(
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
};
match parse_to_token_tree(
file_id.edition(),
SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
SyntaxContextId::ROOT,
&db.file_text(file_id.file_id()),
) {
Some(it) => ExpandResult::ok(it),
None => ExpandResult::new(
tt::Subtree::empty(DelimSpan { open: span, close: span }),
ExpandError::other(span, "failed to parse included file"),
),
}
let span_map = db.real_span_map(file_id);
// FIXME: Parse errors
ExpandResult::ok(syntax_node_to_token_tree(
&db.parse(file_id).syntax_node(),
SpanMap::RealSpanMap(span_map),
span,
syntax_bridge::DocCommentDesugarMode::ProcMacro,
))
}
pub fn include_input_to_file_id(

View file

@ -35,7 +35,7 @@ type MacroArgResult = (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
/// an error will be emitted.
///
/// Actual max for `analysis-stats .` at some point: 30672.
static TOKEN_LIMIT: Limit = Limit::new(1_048_576);
static TOKEN_LIMIT: Limit = Limit::new(2_097_152);
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenExpander {

View file

@ -227,7 +227,7 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
&'a SyntaxContextData,
);
impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
impl std::fmt::Debug for SyntaxContextDebug<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fancy_debug(self.2, self.1, self.0, f)
}

View file

@ -165,40 +165,73 @@ pub enum ExpandErrorKind {
}
impl ExpandError {
pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
self.inner.0.render_to_string(db)
}
}
pub struct RenderedExpandError {
pub message: String,
pub error: bool,
pub kind: &'static str,
}
impl RenderedExpandError {
const GENERAL_KIND: &str = "macro-error";
}
impl ExpandErrorKind {
pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
match self {
ExpandErrorKind::ProcMacroAttrExpansionDisabled => {
("procedural attribute macro expansion is disabled".to_owned(), false)
}
ExpandErrorKind::MacroDisabled => {
("proc-macro is explicitly disabled".to_owned(), false)
}
ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError {
message: "procedural attribute macro expansion is disabled".to_owned(),
error: false,
kind: "proc-macros-disabled",
},
ExpandErrorKind::MacroDisabled => RenderedExpandError {
message: "proc-macro is explicitly disabled".to_owned(),
error: false,
kind: "proc-macro-disabled",
},
&ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
match db.proc_macros().get_error_for_crate(def_crate) {
Some((e, hard_err)) => (e.to_owned(), hard_err),
None => (
format!(
"internal error: proc-macro map is missing error entry for crate {def_crate:?}"
),
true,
),
Some((e, hard_err)) => RenderedExpandError {
message: e.to_owned(),
error: hard_err,
kind: RenderedExpandError::GENERAL_KIND,
},
None => RenderedExpandError {
message: format!("internal error: proc-macro map is missing error entry for crate {def_crate:?}"),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
}
}
ExpandErrorKind::MacroDefinition => {
("macro definition has parse errors".to_owned(), true)
}
ExpandErrorKind::Mbe(e) => (e.to_string(), true),
ExpandErrorKind::RecursionOverflow => {
("overflow expanding the original macro".to_owned(), true)
}
ExpandErrorKind::Other(e) => ((**e).to_owned(), true),
ExpandErrorKind::ProcMacroPanic(e) => (format!("proc-macro panicked: {e}"), true),
ExpandErrorKind::MacroDefinition => RenderedExpandError {
message: "macro definition has parse errors".to_owned(),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
ExpandErrorKind::Mbe(e) => RenderedExpandError {
message: e.to_string(),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
ExpandErrorKind::RecursionOverflow => RenderedExpandError {
message: "overflow expanding the original macro".to_owned(),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
ExpandErrorKind::Other(e) => RenderedExpandError {
message: (**e).to_owned(),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
ExpandErrorKind::ProcMacroPanic(e) => RenderedExpandError {
message: format!("proc-macro panicked: {e}"),
error: true,
kind: RenderedExpandError::GENERAL_KIND,
},
}
}
}

View file

@ -18,6 +18,8 @@ use syntax::utils::is_raw_identifier;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Name {
symbol: Symbol,
// If you are making this carry actual hygiene, beware that the special handling for variables and labels
// in bodies can go.
ctx: (),
}

View file

@ -114,7 +114,7 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
}
#[allow(private_bounds)]
impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
impl<T: TrackAutoderefSteps> Autoderef<'_, '_, T> {
pub(crate) fn step_count(&self) -> usize {
self.steps.len()
}

View file

@ -521,7 +521,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
}
}
impl<'a> ChalkContext<'a> {
impl ChalkContext<'_> {
fn edition(&self) -> Edition {
self.db.crate_graph()[self.krate].edition
}
@ -615,8 +615,9 @@ pub(crate) fn associated_ty_data_query(
let type_alias_data = db.type_alias_data(type_alias);
let generic_params = generics(db.upcast(), type_alias.into());
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
let ctx =
crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())

View file

@ -3,7 +3,7 @@
use base_db::{ra_salsa::Cycle, CrateId};
use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
use hir_def::{
body::Body,
body::{Body, HygieneId},
hir::{Expr, ExprId},
path::Path,
resolver::{Resolver, ValueNs},
@ -11,7 +11,7 @@ use hir_def::{
ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
};
use hir_expand::Lookup;
use stdx::{never, IsNoneOr};
use stdx::never;
use triomphe::Arc;
use crate::{
@ -80,7 +80,7 @@ pub(crate) fn path_to_const<'g>(
debruijn: DebruijnIndex,
expected_ty: Ty,
) -> Option<Const> {
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path, HygieneId::ROOT) {
Some(ValueNs::GenericParam(p)) => {
let ty = db.const_param_ty(p);
let value = match mode {
@ -287,7 +287,7 @@ pub(crate) fn const_eval_discriminant_variant(
}
let repr = db.enum_data(loc.parent).repr;
let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed());
let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
let mir_body = db.monomorphized_mir_body(
def,
@ -319,7 +319,7 @@ pub(crate) fn eval_to_const(
return true;
}
let mut r = false;
body[expr].walk_child_exprs(|idx| r |= has_closure(body, idx));
body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx));
r
}
if has_closure(ctx.body, expr) {

View file

@ -95,7 +95,8 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
let mut err = String::new();
let span_formatter = |file, range| format!("{file:?} {range:?}");
let edition = db.crate_graph()[db.test_crate()].edition;
let edition =
db.crate_graph()[*db.crate_graph().crates_in_topological_order().last().unwrap()].edition;
match e {
ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
@ -2896,7 +2897,7 @@ fn recursive_adt() {
{
const VARIANT_TAG_TREE: TagTree = TagTree::Choice(
&[
TagTree::Leaf,
TAG_TREE,
],
);
VARIANT_TAG_TREE
@ -2905,6 +2906,6 @@ fn recursive_adt() {
TAG_TREE
};
"#,
|e| matches!(e, ConstEvalError::MirEvalError(MirEvalError::StackOverflow)),
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::Loop)),
);
}

View file

@ -309,7 +309,7 @@ impl<'a> DeclValidator<'a> {
/// Check incorrect names for struct fields.
fn validate_struct_fields(&mut self, struct_id: StructId) {
let data = self.db.struct_data(struct_id);
let VariantData::Record(fields) = data.variant_data.as_ref() else {
let VariantData::Record { fields, .. } = data.variant_data.as_ref() else {
return;
};
let edition = self.edition(struct_id);
@ -469,7 +469,7 @@ impl<'a> DeclValidator<'a> {
/// Check incorrect names for fields of enum variant.
fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
let variant_data = self.db.enum_variant_data(variant_id);
let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else {
return;
};
let edition = self.edition(variant_id);

View file

@ -289,10 +289,12 @@ impl ExprValidator {
match &self.body[scrutinee_expr] {
Expr::UnaryOp { op: UnaryOp::Deref, .. } => false,
Expr::Path(path) => {
let value_or_partial = self
.owner
.resolver(db.upcast())
.resolve_path_in_value_ns_fully(db.upcast(), path);
let value_or_partial =
self.owner.resolver(db.upcast()).resolve_path_in_value_ns_fully(
db.upcast(),
path,
self.body.expr_path_hygiene(scrutinee_expr),
);
value_or_partial.map_or(true, |v| !matches!(v, ValueNs::StaticId(_)))
}
Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) {
@ -546,10 +548,7 @@ pub fn record_literal_missing_fields(
expr: &Expr,
) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
let (fields, exhaustive) = match expr {
Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => {
let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() };
(fields, exhaustive)
}
Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
_ => return None,
};

View file

@ -341,7 +341,7 @@ impl HirDisplay for Pat {
};
let variant_data = variant.variant_data(f.db.upcast());
if let VariantData::Record(rec_fields) = &*variant_data {
if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
write!(f, " {{ ")?;
let mut printed = 0;

View file

@ -519,7 +519,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
}
}
impl<'db> fmt::Debug for MatchCheckCtx<'db> {
impl fmt::Debug for MatchCheckCtx<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish()
}

View file

@ -3,7 +3,7 @@
use hir_def::{
body::Body,
hir::{Expr, ExprId, UnaryOp},
hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp},
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
type_ref::Rawness,
DefWithBodyId,
@ -16,7 +16,7 @@ use crate::{
/// Returns `(unsafe_exprs, fn_is_unsafe)`.
///
/// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, bool) {
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) {
let _p = tracing::info_span!("missing_unsafe").entered();
let mut res = Vec::new();
@ -32,7 +32,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
let infer = db.infer(def);
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
if !expr.inside_unsafe_block {
res.push(expr.expr);
res.push(expr.node);
}
});
@ -40,7 +40,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
}
pub struct UnsafeExpr {
pub expr: ExprId,
pub node: ExprOrPatId,
pub inside_unsafe_block: bool,
}
@ -75,26 +75,29 @@ fn walk_unsafe(
inside_unsafe_block: bool,
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
) {
let mut mark_unsafe_path = |path, node| {
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
let hygiene = body.expr_or_pat_path_hygiene(node);
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene);
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
let static_data = db.static_data(id);
if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block });
}
}
resolver.reset_to_guard(g);
};
let expr = &body.exprs[current];
match expr {
&Expr::Call { callee, .. } => {
if let Some(func) = infer[callee].as_fn_def(db) {
if is_fn_unsafe_to_call(db, func) {
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
}
Expr::Path(path) => {
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
let static_data = db.static_data(id);
if static_data.mutable || static_data.is_extern {
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
}
}
resolver.reset_to_guard(g);
}
Expr::Path(path) => mark_unsafe_path(path, current.into()),
Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
if let Expr::Path(_) = body.exprs[*expr] {
// Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
@ -108,23 +111,30 @@ fn walk_unsafe(
.map(|(func, _)| is_fn_unsafe_to_call(db, func))
.unwrap_or(false)
{
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
Expr::Unsafe { .. } => {
return expr.walk_child_exprs(|child| {
return body.walk_child_exprs(current, |child| {
walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
});
}
&Expr::Assignment { target, value: _ } => {
body.walk_pats(target, &mut |pat| {
if let Pat::Path(path) = &body[pat] {
mark_unsafe_path(path, pat.into());
}
});
}
_ => {}
}
expr.walk_child_exprs(|child| {
body.walk_child_exprs(current, |child| {
walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb);
});
}

View file

@ -19,7 +19,9 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget},
nameres::DefMap,
path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
type_ref::{
TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
},
visibility::Visibility,
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
ModuleId, TraitId,
@ -806,7 +808,7 @@ fn render_variant_after_name(
memory_map: &MemoryMap,
) -> Result<(), HirDisplayError> {
match data {
VariantData::Record(fields) | VariantData::Tuple(fields) => {
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
let ty = field_types[id].clone().substitute(Interner, subst);
@ -817,7 +819,7 @@ fn render_variant_after_name(
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
};
let mut it = fields.iter();
if matches!(data, VariantData::Record(_)) {
if matches!(data, VariantData::Record { .. }) {
write!(f, " {{")?;
if let Some((id, data)) = it.next() {
write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
@ -1897,100 +1899,150 @@ pub fn write_visibility(
}
}
impl HirDisplay for TypeRef {
pub trait HirDisplayWithTypesMap {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError>;
}
impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
T::hir_fmt(&**self, f, types_map)
}
}
pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
value: T,
types_map: &'a TypesMap,
) -> impl HirDisplay + 'a {
TypesMapAdapter(value, types_map)
}
struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
impl<'a, T> TypesMapAdapter<'a, T> {
fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
move |value| TypesMapAdapter(value, types_map)
}
}
impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match self {
T::hir_fmt(&self.0, f, self.1)
}
}
impl HirDisplayWithTypesMap for TypeRefId {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match &types_map[*self] {
TypeRef::Never => write!(f, "!")?,
TypeRef::Placeholder => write!(f, "_")?,
TypeRef::Tuple(elems) => {
write!(f, "(")?;
f.write_joined(elems, ", ")?;
f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
if elems.len() == 1 {
write!(f, ",")?;
}
write!(f, ")")?;
}
TypeRef::Path(path) => path.hir_fmt(f)?,
TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
TypeRef::RawPtr(inner, mutability) => {
let mutability = match mutability {
hir_def::type_ref::Mutability::Shared => "*const ",
hir_def::type_ref::Mutability::Mut => "*mut ",
};
write!(f, "{mutability}")?;
inner.hir_fmt(f)?;
inner.hir_fmt(f, types_map)?;
}
TypeRef::Reference(inner, lifetime, mutability) => {
let mutability = match mutability {
TypeRef::Reference(ref_) => {
let mutability = match ref_.mutability {
hir_def::type_ref::Mutability::Shared => "",
hir_def::type_ref::Mutability::Mut => "mut ",
};
write!(f, "&")?;
if let Some(lifetime) = lifetime {
if let Some(lifetime) = &ref_.lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
}
write!(f, "{mutability}")?;
inner.hir_fmt(f)?;
ref_.ty.hir_fmt(f, types_map)?;
}
TypeRef::Array(inner, len) => {
TypeRef::Array(array) => {
write!(f, "[")?;
inner.hir_fmt(f)?;
write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
array.ty.hir_fmt(f, types_map)?;
write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
}
TypeRef::Slice(inner) => {
write!(f, "[")?;
inner.hir_fmt(f)?;
inner.hir_fmt(f, types_map)?;
write!(f, "]")?;
}
&TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => {
if is_unsafe {
TypeRef::Fn(fn_) => {
if fn_.is_unsafe() {
write!(f, "unsafe ")?;
}
if let Some(abi) = abi {
if let Some(abi) = fn_.abi() {
f.write_str("extern \"")?;
f.write_str(abi.as_str())?;
f.write_str("\" ")?;
}
write!(f, "fn(")?;
if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() {
for index in 0..function_parameters.len() {
let (param_name, param_type) = &function_parameters[index];
if let Some(name) = param_name {
write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
}
param_type.hir_fmt(f)?;
param_type.hir_fmt(f, types_map)?;
if index != function_parameters.len() - 1 {
write!(f, ", ")?;
}
}
if is_varargs {
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
if fn_.is_varargs() {
write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?;
}
write!(f, ")")?;
match &return_type {
match &types_map[*return_type] {
TypeRef::Tuple(tup) if tup.is_empty() => {}
_ => {
write!(f, " -> ")?;
return_type.hir_fmt(f)?;
return_type.hir_fmt(f, types_map)?;
}
}
}
}
TypeRef::ImplTrait(bounds) => {
write!(f, "impl ")?;
f.write_joined(bounds, " + ")?;
f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
}
TypeRef::DynTrait(bounds) => {
write!(f, "dyn ")?;
f.write_joined(bounds, " + ")?;
f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
}
TypeRef::Macro(macro_call) => {
let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id);
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = hir_def::lower::LowerCtx::new(
f.db.upcast(),
macro_call.file_id,
&mut types_map,
&mut types_source_map,
);
let macro_call = macro_call.to_node(f.db.upcast());
match macro_call.path() {
Some(path) => match Path::from_src(&ctx, path) {
Some(path) => path.hir_fmt(f)?,
Some(path) => path.hir_fmt(f, &types_map)?,
None => write!(f, "{{macro}}")?,
},
None => write!(f, "{{macro}}")?,
@ -2003,15 +2055,19 @@ impl HirDisplay for TypeRef {
}
}
impl HirDisplay for TypeBound {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
impl HirDisplayWithTypesMap for TypeBound {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match self {
TypeBound::Path(path, modifier) => {
match modifier {
TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(f, "?")?,
}
path.hir_fmt(f)
path.hir_fmt(f, types_map)
}
TypeBound::Lifetime(lifetime) => {
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@ -2023,19 +2079,36 @@ impl HirDisplay for TypeBound {
"for<{}> ",
lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
)?;
path.hir_fmt(f)
path.hir_fmt(f, types_map)
}
TypeBound::Use(args) => {
let edition = f.edition();
write!(
f,
"use<{}> ",
args.iter()
.map(|it| match it {
UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
})
.format(", ")
)
}
TypeBound::Error => write!(f, "{{error}}"),
}
}
}
impl HirDisplay for Path {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
impl HirDisplayWithTypesMap for Path {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match (self.type_anchor(), self.kind()) {
(Some(anchor), _) => {
write!(f, "<")?;
anchor.hir_fmt(f)?;
anchor.hir_fmt(f, types_map)?;
write!(f, ">")?;
}
(_, PathKind::Plain) => {}
@ -2078,7 +2151,7 @@ impl HirDisplay for Path {
});
if let Some(ty) = trait_self_ty {
write!(f, "<")?;
ty.hir_fmt(f)?;
ty.hir_fmt(f, types_map)?;
write!(f, " as ")?;
// Now format the path of the trait...
}
@ -2094,21 +2167,26 @@ impl HirDisplay for Path {
if generic_args.desugared_from_fn {
// First argument will be a tuple, which already includes the parentheses.
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
&generic_args.args[0]
{
let tuple = match generic_args.args[0] {
hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
TypeRef::Tuple(it) => Some(it),
_ => None,
},
_ => None,
};
if let Some(v) = tuple {
if v.len() == 1 {
write!(f, "(")?;
v[0].hir_fmt(f)?;
v[0].hir_fmt(f, types_map)?;
write!(f, ")")?;
} else {
generic_args.args[0].hir_fmt(f)?;
generic_args.args[0].hir_fmt(f, types_map)?;
}
}
if let Some(ret) = &generic_args.bindings[0].type_ref {
if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
if let Some(ret) = generic_args.bindings[0].type_ref {
if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
write!(f, " -> ")?;
ret.hir_fmt(f)?;
ret.hir_fmt(f, types_map)?;
}
}
return Ok(());
@ -2123,7 +2201,7 @@ impl HirDisplay for Path {
} else {
write!(f, ", ")?;
}
arg.hir_fmt(f)?;
arg.hir_fmt(f, types_map)?;
}
for binding in generic_args.bindings.iter() {
if first {
@ -2136,11 +2214,14 @@ impl HirDisplay for Path {
match &binding.type_ref {
Some(ty) => {
write!(f, " = ")?;
ty.hir_fmt(f)?
ty.hir_fmt(f, types_map)?
}
None => {
write!(f, ": ")?;
f.write_joined(binding.bounds.iter(), " + ")?;
f.write_joined(
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
" + ",
)?;
}
}
}
@ -2162,10 +2243,14 @@ impl HirDisplay for Path {
}
}
impl HirDisplay for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match self {
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
hir_def::path::GenericArg::Const(c) => {
write!(f, "{}", c.display(f.db.upcast(), f.edition()))
}

View file

@ -266,7 +266,7 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>(
trait_self_param_idx: usize,
allow_self_projection: AllowSelfProjection,
}
impl<'a> TypeVisitor<Interner> for IllegalSelfTypeVisitor<'a> {
impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> {
type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {

View file

@ -16,12 +16,13 @@ use hir_def::{
GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
TypeParamProvenance,
},
type_ref::TypesMap,
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
use intern::Interned;
use itertools::chain;
use stdx::TupleExt;
use triomphe::Arc;
use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
@ -34,7 +35,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
#[derive(Clone, Debug)]
pub(crate) struct Generics {
def: GenericDefId,
params: Interned<GenericParams>,
params: Arc<GenericParams>,
parent_generics: Option<Box<Generics>>,
has_trait_self_param: bool,
}
@ -85,6 +86,18 @@ impl Generics {
self.iter_self().chain(self.iter_parent())
}
pub(crate) fn iter_with_types_map(
&self,
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
self.iter_parent().zip(
self.parent_generics()
.into_iter()
.flat_map(|it| std::iter::repeat(&it.params.types_map)),
),
)
}
/// Iterate over the params without parent params.
pub(crate) fn iter_self(
&self,

View file

@ -33,7 +33,7 @@ use chalk_ir::{
};
use either::Either;
use hir_def::{
body::Body,
body::{Body, HygieneId},
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@ -41,7 +41,7 @@ use hir_def::{
layout::Integer,
path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::{LifetimeRef, TypeRef},
type_ref::{LifetimeRef, TypeRefId, TypesMap},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
};
@ -228,7 +228,7 @@ pub enum InferenceDiagnostic {
id: ExprOrPatId,
},
UnresolvedIdent {
expr: ExprId,
id: ExprOrPatId,
},
// FIXME: This should be emitted in body lowering
BreakOutsideOfLoop {
@ -482,12 +482,27 @@ impl InferenceResult {
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
self.variant_resolutions.get(&id.into()).copied()
}
pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> {
match id {
ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id),
ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id),
}
}
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
self.assoc_resolutions.get(&id.into()).cloned()
}
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
self.assoc_resolutions.get(&id.into()).cloned()
}
pub fn assoc_resolutions_for_expr_or_pat(
&self,
id: ExprOrPatId,
) -> Option<(AssocItemId, Substitution)> {
match id {
ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id),
ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
}
}
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
self.type_mismatches.get(&expr.into())
}
@ -506,6 +521,12 @@ impl InferenceResult {
pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
self.closure_info.get(closure).unwrap()
}
pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> {
match id {
ExprOrPatId::ExprId(id) => self.type_of_expr.get(id),
ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
}
}
}
impl Index<ExprId> for InferenceResult {
@ -524,6 +545,14 @@ impl Index<PatId> for InferenceResult {
}
}
impl Index<ExprOrPatId> for InferenceResult {
type Output = Ty;
fn index(&self, id: ExprOrPatId) -> &Ty {
self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown)
}
}
impl Index<BindingId> for InferenceResult {
type Output = Ty;
@ -561,6 +590,9 @@ pub(crate) struct InferenceContext<'a> {
diverges: Diverges,
breakables: Vec<BreakableContext>,
/// Whether we are inside the pattern of a destructuring assignment.
inside_assignment: bool,
deferred_cast_checks: Vec<CastCheck>,
// fields related to closure capture
@ -656,6 +688,7 @@ impl<'a> InferenceContext<'a> {
current_closure: None,
deferred_closures: FxHashMap::default(),
closure_dependencies: FxHashMap::default(),
inside_assignment: false,
}
}
@ -825,7 +858,7 @@ impl<'a> InferenceContext<'a> {
}
fn collect_const(&mut self, data: &ConstData) {
let return_ty = self.make_ty(&data.type_ref);
let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Constants might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@ -834,7 +867,7 @@ impl<'a> InferenceContext<'a> {
}
fn collect_static(&mut self, data: &StaticData) {
let return_ty = self.make_ty(&data.type_ref);
let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Statics might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@ -844,11 +877,11 @@ impl<'a> InferenceContext<'a> {
fn collect_fn(&mut self, func: FunctionId) {
let data = self.db.function_data(func);
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
.with_type_param_mode(ParamLoweringMode::Placeholder)
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
let mut param_tys =
data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
ctx.type_param_mode(ParamLoweringMode::Placeholder)
.impl_trait_mode(ImplTraitLoweringMode::Param);
data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
});
// Check if function contains a va_list, if it does then we append it to the parameter types
// that are collected from the function data
if data.is_varargs() {
@ -883,12 +916,13 @@ impl<'a> InferenceContext<'a> {
tait_candidates.insert(ty);
}
}
let return_ty = &*data.ret_type;
let return_ty = data.ret_type;
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
.with_type_param_mode(ParamLoweringMode::Placeholder)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
let return_ty = ctx.lower_ty(return_ty);
let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
ctx.type_param_mode(ParamLoweringMode::Placeholder)
.impl_trait_mode(ImplTraitLoweringMode::Opaque)
.lower_ty(return_ty)
});
let return_ty = self.insert_type_vars(return_ty);
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@ -1022,7 +1056,7 @@ impl<'a> InferenceContext<'a> {
non_assocs: FxHashMap<OpaqueTyId, Ty>,
}
impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> {
type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
@ -1192,20 +1226,43 @@ impl<'a> InferenceContext<'a> {
self.result.diagnostics.push(diagnostic);
}
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let ty = ctx.lower_ty(type_ref);
fn with_ty_lowering<R>(
&self,
types_map: &TypesMap,
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
) -> R {
let mut ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
types_map,
self.owner.into(),
);
f(&mut ctx)
}
fn with_body_ty_lowering<R>(
&self,
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
) -> R {
self.with_ty_lowering(&self.body.types, f)
}
fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty)
}
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
self.make_ty(type_ref, &self.body.types)
}
fn err_ty(&self) -> Ty {
self.result.standard_types.unknown.clone()
}
fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let lt = ctx.lower_lifetime(lifetime_ref);
let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
self.insert_type_vars(lt)
}
@ -1363,9 +1420,14 @@ impl<'a> InferenceContext<'a> {
Some(path) => path,
None => return (self.err_ty(), None),
};
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
&self.body.types,
self.owner.into(),
);
let (resolution, unresolved) = if value_ns {
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) {
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
Some(ResolveValueResult::ValueNs(value, _)) => match value {
ValueNs::EnumVariantId(var) => {
let substs = ctx.substs_from_path(path, var.into(), true);

View file

@ -11,11 +11,12 @@ use either::Either;
use hir_def::{
data::adt::VariantData,
hir::{
Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement,
UnaryOp,
Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
Statement, UnaryOp,
},
lang_item::LangItem,
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
path::Path,
resolver::ValueNs,
DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
};
use hir_expand::name::Name;
@ -282,11 +283,11 @@ impl CapturedItem {
ProjectionElem::Deref => {}
ProjectionElem::Field(Either::Left(f)) => {
match &*f.parent.variant_data(db.upcast()) {
VariantData::Record(fields) => {
VariantData::Record { fields, .. } => {
result.push('_');
result.push_str(fields[f.local_id].name.as_str())
}
VariantData::Tuple(fields) => {
VariantData::Tuple { fields, .. } => {
let index = fields.iter().position(|it| it.0 == f.local_id);
if let Some(index) = index {
format_to!(result, "_{index}");
@ -324,12 +325,12 @@ impl CapturedItem {
ProjectionElem::Field(Either::Left(f)) => {
let variant_data = f.parent.variant_data(db.upcast());
match &*variant_data {
VariantData::Record(fields) => format_to!(
VariantData::Record { fields, .. } => format_to!(
result,
".{}",
fields[f.local_id].name.display(db.upcast(), edition)
),
VariantData::Tuple(fields) => format_to!(
VariantData::Tuple { fields, .. } => format_to!(
result,
".{}",
fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@ -382,8 +383,10 @@ impl CapturedItem {
}
let variant_data = f.parent.variant_data(db.upcast());
let field = match &*variant_data {
VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
VariantData::Tuple(fields) => fields
VariantData::Record { fields, .. } => {
fields[f.local_id].name.as_str().to_owned()
}
VariantData::Tuple { fields, .. } => fields
.iter()
.position(|it| it.0 == f.local_id)
.unwrap_or_default()
@ -508,18 +511,39 @@ impl InferenceContext<'_> {
apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments)
}
/// Pushes the span into `current_capture_span_stack`, *without clearing it first*.
fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> {
if path.type_anchor().is_some() {
return None;
}
let hygiene = self.body.expr_or_pat_path_hygiene(id);
let result = self
.resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene)
.and_then(|result| match result {
ValueNs::LocalBinding(binding) => {
let mir_span = match id {
ExprOrPatId::ExprId(id) => MirSpan::ExprId(id),
ExprOrPatId::PatId(id) => MirSpan::PatId(id),
};
self.current_capture_span_stack.push(mir_span);
Some(HirPlace { local: binding, projections: Vec::new() })
}
_ => None,
});
result
}
/// Changes `current_capture_span_stack` to contain the stack of spans for this expr.
fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
self.current_capture_span_stack.clear();
match &self.body[tgt_expr] {
Expr::Path(p) => {
let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
if let Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(b), _)) =
resolver.resolve_path_in_value_ns(self.db.upcast(), p)
{
self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
return Some(HirPlace { local: b, projections: vec![] });
}
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
let result = self.path_place(p, tgt_expr.into());
self.resolver.reset_to_guard(resolver_guard);
return result;
}
Expr::Field { expr, name: _ } => {
let mut place = self.place_of_expr(*expr)?;
@ -590,6 +614,16 @@ impl InferenceContext<'_> {
}
}
fn mutate_path_pat(&mut self, path: &Path, id: PatId) {
if let Some(place) = self.path_place(path, id.into()) {
self.add_capture(
place,
CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
);
self.current_capture_span_stack.pop(); // Remove the pattern span.
}
}
fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
if let Some(place) = place {
self.add_capture(
@ -715,14 +749,14 @@ impl InferenceContext<'_> {
Statement::Expr { expr, has_semi: _ } => {
self.consume_expr(*expr);
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
self.consume_expr(*tail);
}
}
Expr::Call { callee, args, is_assignee_expr: _ } => {
Expr::Call { callee, args } => {
self.consume_expr(*callee);
self.consume_exprs(args.iter().copied());
}
@ -838,7 +872,7 @@ impl InferenceContext<'_> {
self.consume_expr(expr);
}
}
Expr::Index { base, index, is_assignee_expr: _ } => {
Expr::Index { base, index } => {
self.select_from_expr(*base);
self.consume_expr(*index);
}
@ -862,10 +896,30 @@ impl InferenceContext<'_> {
}));
self.current_captures = cc;
}
Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ })
| Expr::Tuple { exprs, is_assignee_expr: _ } => {
Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => {
self.consume_exprs(exprs.iter().copied())
}
&Expr::Assignment { target, value } => {
self.walk_expr(value);
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
match self.place_of_expr(value) {
Some(rhs_place) => {
self.inside_assignment = true;
self.consume_with_pat(rhs_place, target);
self.inside_assignment = false;
}
None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] {
Pat::Path(path) => self.mutate_path_pat(path, pat),
&Pat::Expr(expr) => {
let place = self.place_of_expr(expr);
self.mutate_expr(expr, place);
}
_ => {}
}),
}
self.resolver.reset_to_guard(resolver_guard);
}
Expr::Missing
| Expr::Continue { .. }
@ -903,6 +957,7 @@ impl InferenceContext<'_> {
| Pat::Missing
| Pat::Wild
| Pat::Tuple { .. }
| Pat::Expr(_)
| Pat::Or(_) => (),
Pat::TupleStruct { .. } | Pat::Record { .. } => {
if let Some(variant) = self.result.variant_resolution_for_pat(p) {
@ -1122,11 +1177,15 @@ impl InferenceContext<'_> {
}
}
}
Pat::Range { .. }
| Pat::Slice { .. }
| Pat::ConstBlock(_)
| Pat::Path(_)
| Pat::Lit(_) => self.consume_place(place),
Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => {
self.consume_place(place)
}
Pat::Path(path) => {
if self.inside_assignment {
self.mutate_path_pat(path, tgt_pat);
}
self.consume_place(place);
}
&Pat::Bind { id, subpat: _ } => {
let mode = self.result.binding_modes[tgt_pat];
let capture_kind = match mode {
@ -1180,6 +1239,15 @@ impl InferenceContext<'_> {
self.current_capture_span_stack.pop();
}
Pat::Box { .. } => (), // not supported
&Pat::Expr(expr) => {
self.consume_place(place);
let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack);
let old_inside_assignment = mem::replace(&mut self.inside_assignment, false);
let lhs_place = self.place_of_expr(expr);
self.mutate_expr(expr, lhs_place);
self.inside_assignment = old_inside_assignment;
self.current_capture_span_stack = pat_capture_span_stack;
}
}
}
self.current_capture_span_stack

View file

@ -9,8 +9,8 @@ use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKin
use either::Either;
use hir_def::{
hir::{
ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId,
Literal, Pat, PatId, Statement, UnaryOp,
ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId,
LabelId, Literal, Pat, PatId, Statement, UnaryOp,
},
lang_item::{LangItem, LangItemTarget},
path::{GenericArg, GenericArgs, Path},
@ -188,6 +188,9 @@ impl InferenceContext<'_> {
| Pat::ConstBlock(_)
| Pat::Record { .. }
| Pat::Missing => true,
Pat::Expr(_) => unreachable!(
"we don't call pat_guaranteed_to_constitute_read_for_never() with assignments"
),
}
}
@ -195,10 +198,14 @@ impl InferenceContext<'_> {
match &self.body[expr] {
// Lang item paths cannot currently be local variables or statics.
Expr::Path(Path::LangItem(_, _)) => false,
Expr::Path(Path::Normal { type_anchor: Some(_), .. }) => false,
Expr::Path(Path::Normal(path)) => path.type_anchor().is_none(),
Expr::Path(path) => self
.resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), path)
.resolve_path_in_value_ns_fully(
self.db.upcast(),
path,
self.body.expr_path_hygiene(expr),
)
.map_or(true, |res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))),
Expr::Underscore => true,
Expr::UnaryOp { op: UnaryOp::Deref, .. } => true,
@ -223,6 +230,7 @@ impl InferenceContext<'_> {
| Expr::Const(..)
| Expr::UnaryOp { .. }
| Expr::BinaryOp { .. }
| Expr::Assignment { .. }
| Expr::Yield { .. }
| Expr::Cast { .. }
| Expr::Async { .. }
@ -374,7 +382,7 @@ impl InferenceContext<'_> {
// collect explicitly written argument types
for arg_type in arg_types.iter() {
let arg_ty = match arg_type {
Some(type_ref) => self.make_ty(type_ref),
Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(),
};
sig_tys.push(arg_ty);
@ -382,7 +390,7 @@ impl InferenceContext<'_> {
// add return type
let ret_ty = match ret_type {
Some(type_ref) => self.make_ty(type_ref),
Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(),
};
if let ClosureKind::Async = closure_kind {
@ -609,23 +617,7 @@ impl InferenceContext<'_> {
coerce.complete(self)
}
}
Expr::Path(p) => {
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
let ty = match self.infer_path(p, tgt_expr.into()) {
Some(ty) => ty,
None => {
if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self())
{
self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
expr: tgt_expr,
});
}
self.err_ty()
}
};
self.resolver.reset_to_guard(g);
ty
}
Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr),
&Expr::Continue { label } => {
if find_continuable(&mut self.breakables, label).is_none() {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
@ -794,7 +786,7 @@ impl InferenceContext<'_> {
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
}
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref);
let cast_ty = self.make_body_ty(*type_ref);
let expr_ty = self.infer_expr(
*expr,
&Expectation::Castable(cast_ty.clone()),
@ -892,36 +884,6 @@ impl InferenceContext<'_> {
}
}
Expr::BinaryOp { lhs, rhs, op } => match op {
Some(BinaryOp::Assignment { op: None }) => {
let lhs = *lhs;
let is_ordinary = match &self.body[lhs] {
Expr::Array(_)
| Expr::RecordLit { .. }
| Expr::Tuple { .. }
| Expr::Underscore => false,
Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
_ => true,
};
// In ordinary (non-destructuring) assignments, the type of
// `lhs` must be inferred first so that the ADT fields
// instantiations in RHS can be coerced to it. Note that this
// cannot happen in destructuring assignments because of how
// they are desugared.
if is_ordinary {
// LHS of assignment doesn't constitute reads.
let lhs_ty = self.infer_expr(lhs, &Expectation::none(), ExprIsRead::No);
self.infer_expr_coerce(
*rhs,
&Expectation::has_type(lhs_ty),
ExprIsRead::No,
);
} else {
let rhs_ty = self.infer_expr(*rhs, &Expectation::none(), ExprIsRead::Yes);
self.infer_assignee_expr(lhs, &rhs_ty);
}
self.result.standard_types.unit.clone()
}
Some(BinaryOp::LogicOp(_)) => {
let bool_ty = self.result.standard_types.bool_.clone();
self.infer_expr_coerce(
@ -942,6 +904,35 @@ impl InferenceContext<'_> {
Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
_ => self.err_ty(),
},
&Expr::Assignment { target, value } => {
// In ordinary (non-destructuring) assignments, the type of
// `lhs` must be inferred first so that the ADT fields
// instantiations in RHS can be coerced to it. Note that this
// cannot happen in destructuring assignments because of how
// they are desugared.
let lhs_ty = match &self.body[target] {
// LHS of assignment doesn't constitute reads.
&Pat::Expr(expr) => {
Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No))
}
Pat::Path(path) => Some(self.infer_expr_path(path, target.into(), tgt_expr)),
_ => None,
};
if let Some(lhs_ty) = lhs_ty {
self.write_pat_ty(target, lhs_ty.clone());
self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No);
} else {
let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes);
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
self.inside_assignment = true;
self.infer_top_pat(target, &rhs_ty);
self.inside_assignment = false;
self.resolver.reset_to_guard(resolver_guard);
}
self.result.standard_types.unit.clone()
}
Expr::Range { lhs, rhs, range_type } => {
let lhs_ty =
lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
@ -981,7 +972,7 @@ impl InferenceContext<'_> {
(RangeOp::Inclusive, _, None) => self.err_ty(),
}
}
Expr::Index { base, index, is_assignee_expr } => {
Expr::Index { base, index } => {
let base_ty = self.infer_expr_inner(*base, &Expectation::none(), ExprIsRead::Yes);
let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes);
@ -1017,23 +1008,11 @@ impl InferenceContext<'_> {
self.write_method_resolution(tgt_expr, func, subst);
}
let assoc = self.resolve_ops_index_output();
let res = self.resolve_associated_type_with_params(
self.resolve_associated_type_with_params(
self_ty.clone(),
assoc,
&[index_ty.clone().cast(Interner)],
);
if *is_assignee_expr {
if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) {
let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
.push(self_ty)
.fill(|_| index_ty.clone().cast(Interner))
.build();
self.push_obligation(trait_ref.cast(Interner));
}
}
res
)
} else {
self.err_ty()
}
@ -1151,9 +1130,7 @@ impl InferenceContext<'_> {
},
},
Expr::Underscore => {
// Underscore expressions may only appear in assignee expressions,
// which are handled by `infer_assignee_expr()`.
// Any other underscore expression is an error, we render a specialized diagnostic
// Underscore expression is an error, we render a specialized diagnostic
// to let the user know what type is expected though.
let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty());
self.push_diagnostic(InferenceDiagnostic::TypedHole {
@ -1232,6 +1209,22 @@ impl InferenceContext<'_> {
ty
}
fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty {
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, scope_id);
let ty = match self.infer_path(path, id) {
Some(ty) => ty,
None => {
if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self())
{
self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { id });
}
self.err_ty()
}
};
self.resolver.reset_to_guard(g);
ty
}
fn infer_async_block(
&mut self,
tgt_expr: ExprId,
@ -1482,107 +1475,6 @@ impl InferenceContext<'_> {
}
}
pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
let is_rest_expr = |expr| {
matches!(
&self.body[expr],
Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
)
};
let rhs_ty = self.resolve_ty_shallow(rhs_ty);
let ty = match &self.body[lhs] {
Expr::Tuple { exprs, .. } => {
// We don't consider multiple ellipses. This is analogous to
// `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
}
Expr::Call { callee, args, .. } => {
// Tuple structs
let path = match &self.body[*callee] {
Expr::Path(path) => Some(path),
_ => None,
};
// We don't consider multiple ellipses. This is analogous to
// `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
let ellipsis = args.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
}
Expr::Array(Array::ElementList { elements, .. }) => {
let elem_ty = match rhs_ty.kind(Interner) {
TyKind::Array(st, _) => st.clone(),
_ => self.err_ty(),
};
// There's no need to handle `..` as it cannot be bound.
let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
for e in sub_exprs {
self.infer_assignee_expr(*e, &elem_ty);
}
match rhs_ty.kind(Interner) {
TyKind::Array(_, _) => rhs_ty.clone(),
// Even when `rhs_ty` is not an array type, this assignee
// expression is inferred to be an array (of unknown element
// type and length). This should not be just an error type,
// because we are to compute the unifiability of this type and
// `rhs_ty` in the end of this function to issue type mismatches.
_ => TyKind::Array(
self.err_ty(),
crate::consteval::usize_const(self.db, None, self.resolver.krate()),
)
.intern(Interner),
}
}
Expr::RecordLit { path, fields, .. } => {
let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs, subs)
}
Expr::Underscore => rhs_ty.clone(),
_ => {
// `lhs` is a place expression, a unit struct, or an enum variant.
// LHS of assignment doesn't constitute reads.
let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none(), ExprIsRead::No);
// This is the only branch where this function may coerce any type.
// We are returning early to avoid the unifiability check below.
let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
let ty = match self.coerce(None, &rhs_ty, &lhs_ty, CoerceNever::Yes) {
Ok(ty) => ty,
Err(_) => {
self.result.type_mismatches.insert(
lhs.into(),
TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
);
// `rhs_ty` is returned so no further type mismatches are
// reported because of this mismatch.
rhs_ty
}
};
self.write_expr_ty(lhs, ty.clone());
return ty;
}
};
let ty = self.insert_type_vars_shallow(ty);
if !self.unify(&ty, &rhs_ty) {
self.result
.type_mismatches
.insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
}
self.write_expr_ty(lhs, ty.clone());
ty
}
fn infer_overloadable_binop(
&mut self,
lhs: ExprId,
@ -1706,7 +1598,7 @@ impl InferenceContext<'_> {
Statement::Let { pat, type_ref, initializer, else_branch } => {
let decl_ty = type_ref
.as_ref()
.map(|tr| this.make_ty(tr))
.map(|&tr| this.make_body_ty(tr))
.unwrap_or_else(|| this.table.new_type_var());
let ty = if let Some(expr) = initializer {
@ -1764,7 +1656,7 @@ impl InferenceContext<'_> {
);
}
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
@ -2249,7 +2141,8 @@ impl InferenceContext<'_> {
kind_id,
args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
self,
|this, type_ref| this.make_ty(type_ref),
&self.body.types,
|this, type_ref| this.make_body_ty(type_ref),
|this, c, ty| {
const_or_path_to_chalk(
this.db,

View file

@ -4,7 +4,8 @@
use chalk_ir::{cast::Cast, Mutability};
use hir_def::{
hir::{
Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp,
Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement,
UnaryOp,
},
lang_item::LangItem,
};
@ -88,7 +89,7 @@ impl InferenceContext<'_> {
Statement::Expr { expr, has_semi: _ } => {
self.infer_mut_expr(*expr, Mutability::Not);
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
@ -96,7 +97,7 @@ impl InferenceContext<'_> {
}
}
Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
| Expr::Call { callee: it, args, is_assignee_expr: _ } => {
| Expr::Call { callee: it, args } => {
self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
}
Expr::Match { expr, arms } => {
@ -120,10 +121,10 @@ impl InferenceContext<'_> {
Expr::Become { expr } => {
self.infer_mut_expr(*expr, Mutability::Not);
}
Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
Expr::RecordLit { path: _, fields, spread } => {
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
}
&Expr::Index { base, index, is_assignee_expr } => {
&Expr::Index { base, index } => {
if mutability == Mutability::Mut {
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
if let Some(index_trait) = self
@ -148,11 +149,8 @@ impl InferenceContext<'_> {
target,
}) = base_adjustments
{
// For assignee exprs `IndexMut` obligations are already applied
if !is_assignee_expr {
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
base_ty = Some(ty.clone());
}
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
base_ty = Some(ty.clone());
}
*mutability = Mutability::Mut;
}
@ -233,6 +231,14 @@ impl InferenceContext<'_> {
self.infer_mut_expr(*lhs, Mutability::Mut);
self.infer_mut_expr(*rhs, Mutability::Not);
}
&Expr::Assignment { target, value } => {
self.body.walk_pats(target, &mut |pat| match self.body[pat] {
Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut),
Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not),
_ => {}
});
self.infer_mut_expr(value, Mutability::Not);
}
Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs })
| Expr::BinaryOp { lhs, rhs, op: _ }
| Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => {
@ -242,8 +248,7 @@ impl InferenceContext<'_> {
Expr::Closure { body, .. } => {
self.infer_mut_expr(*body, Mutability::Not);
}
Expr::Tuple { exprs, is_assignee_expr: _ }
| Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => {
Expr::Tuple { exprs } | Expr::Array(Array::ElementList { elements: exprs }) => {
self.infer_mut_not_expr_iter(exprs.iter().copied());
}
// These don't need any action, as they don't have sub expressions

View file

@ -4,7 +4,7 @@ use std::iter::repeat_with;
use hir_def::{
body::Body,
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
path::Path,
};
use hir_expand::name::Name;
@ -12,63 +12,28 @@ use stdx::TupleExt;
use crate::{
consteval::{try_const_usize, usize_const},
infer::{expr::ExprIsRead, BindingMode, Expectation, InferenceContext, TypeMismatch},
infer::{
coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext,
TypeMismatch,
},
lower::lower_to_chalk_mutability,
primitive::UintTy,
static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
TyBuilder, TyExt, TyKind,
};
/// Used to generalize patterns and assignee expressions.
pub(super) trait PatLike: Into<ExprOrPatId> + Copy {
type BindingMode: Copy;
fn infer(
this: &mut InferenceContext<'_>,
id: Self,
expected_ty: &Ty,
default_bm: Self::BindingMode,
) -> Ty;
}
impl PatLike for ExprId {
type BindingMode = ();
fn infer(
this: &mut InferenceContext<'_>,
id: Self,
expected_ty: &Ty,
(): Self::BindingMode,
) -> Ty {
this.infer_assignee_expr(id, expected_ty)
}
}
impl PatLike for PatId {
type BindingMode = BindingMode;
fn infer(
this: &mut InferenceContext<'_>,
id: Self,
expected_ty: &Ty,
default_bm: Self::BindingMode,
) -> Ty {
this.infer_pat(id, expected_ty, default_bm)
}
}
impl InferenceContext<'_> {
/// Infers type for tuple struct pattern or its corresponding assignee expression.
///
/// Ellipses found in the original pattern or expression must be filtered out.
pub(super) fn infer_tuple_struct_pat_like<T: PatLike>(
pub(super) fn infer_tuple_struct_pat_like(
&mut self,
path: Option<&Path>,
expected: &Ty,
default_bm: T::BindingMode,
id: T,
default_bm: BindingMode,
id: PatId,
ellipsis: Option<u32>,
subs: &[T],
subs: &[PatId],
) -> Ty {
let (ty, def) = self.resolve_variant(path, true);
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@ -127,13 +92,13 @@ impl InferenceContext<'_> {
}
};
T::infer(self, subpat, &expected_ty, default_bm);
self.infer_pat(subpat, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for &inner in subs {
T::infer(self, inner, &err_ty, default_bm);
self.infer_pat(inner, &err_ty, default_bm);
}
}
}
@ -142,13 +107,13 @@ impl InferenceContext<'_> {
}
/// Infers type for record pattern or its corresponding assignee expression.
pub(super) fn infer_record_pat_like<T: PatLike>(
pub(super) fn infer_record_pat_like(
&mut self,
path: Option<&Path>,
expected: &Ty,
default_bm: T::BindingMode,
id: T,
subs: impl ExactSizeIterator<Item = (Name, T)>,
default_bm: BindingMode,
id: PatId,
subs: impl ExactSizeIterator<Item = (Name, PatId)>,
) -> Ty {
let (ty, def) = self.resolve_variant(path, false);
if let Some(variant) = def {
@ -197,13 +162,13 @@ impl InferenceContext<'_> {
}
};
T::infer(self, inner, &expected_ty, default_bm);
self.infer_pat(inner, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for (_, inner) in subs {
T::infer(self, inner, &err_ty, default_bm);
self.infer_pat(inner, &err_ty, default_bm);
}
}
}
@ -214,12 +179,12 @@ impl InferenceContext<'_> {
/// Infers type for tuple pattern or its corresponding assignee expression.
///
/// Ellipses found in the original pattern or expression must be filtered out.
pub(super) fn infer_tuple_pat_like<T: PatLike>(
pub(super) fn infer_tuple_pat_like(
&mut self,
expected: &Ty,
default_bm: T::BindingMode,
default_bm: BindingMode,
ellipsis: Option<u32>,
subs: &[T],
subs: &[PatId],
) -> Ty {
let expected = self.resolve_ty_shallow(expected);
let expectations = match expected.as_tuple() {
@ -244,18 +209,20 @@ impl InferenceContext<'_> {
// Process pre
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
*ty = T::infer(self, *pat, ty, default_bm);
*ty = self.infer_pat(*pat, ty, default_bm);
}
// Process post
for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
*ty = T::infer(self, *pat, ty, default_bm);
*ty = self.infer_pat(*pat, ty, default_bm);
}
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner)
}
/// The resolver needs to be updated to the surrounding expression when inside assignment
/// (because there, `Pat::Path` can refer to a variable).
pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
self.infer_pat(pat, expected, BindingMode::default());
}
@ -263,7 +230,14 @@ impl InferenceContext<'_> {
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
if self.is_non_ref_pat(self.body, pat) {
if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
cov_mark::hit!(match_ergonomics_ref);
// When you encounter a `&pat` pattern, reset to Move.
// This is so that `w` is by value: `let (_, &w) = &(1, &2);`
// Destructuring assignments also reset the binding mode and
// don't do match ergonomics.
default_bm = BindingMode::Move;
} else if self.is_non_ref_pat(self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
pat_adjustments.push(expected.clone());
@ -279,11 +253,6 @@ impl InferenceContext<'_> {
pat_adjustments.shrink_to_fit();
self.result.pat_adjustments.insert(pat, pat_adjustments);
}
} else if let Pat::Ref { .. } = &self.body[pat] {
cov_mark::hit!(match_ergonomics_ref);
// When you encounter a `&pat` pattern, reset to Move.
// This is so that `w` is by value: `let (_, &w) = &(1, &2);`
default_bm = BindingMode::Move;
}
// Lose mutability.
@ -320,8 +289,34 @@ impl InferenceContext<'_> {
self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
}
Pat::Path(path) => {
// FIXME update resolver for the surrounding expression
self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty())
let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone());
match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) {
Ok((adjustments, coerced_ty)) => {
if !adjustments.is_empty() {
self.result
.pat_adjustments
.entry(pat)
.or_default()
.extend(adjustments.into_iter().map(|adjust| adjust.target));
}
self.write_pat_ty(pat, coerced_ty);
return self.pat_ty_after_adjustment(pat);
}
Err(_) => {
self.result.type_mismatches.insert(
pat.into(),
TypeMismatch {
expected: expected.clone(),
actual: ty_inserted_vars.clone(),
},
);
self.write_pat_ty(pat, ty);
// We return `expected` to prevent cascading errors. I guess an alternative is to
// not emit type mismatches for error types and emit an error type here.
return expected;
}
}
}
Pat::Bind { id, subpat } => {
return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected);
@ -361,7 +356,40 @@ impl InferenceContext<'_> {
None => self.err_ty(),
},
Pat::ConstBlock(expr) => {
self.infer_expr(*expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes)
let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
let result = self.infer_expr(
*expr,
&Expectation::has_type(expected.clone()),
ExprIsRead::Yes,
);
self.inside_assignment = old_inside_assign;
result
}
Pat::Expr(expr) => {
let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
// LHS of assignment doesn't constitute reads.
let result = self.infer_expr_coerce(
*expr,
&Expectation::has_type(expected.clone()),
ExprIsRead::No,
);
// We are returning early to avoid the unifiability check below.
let lhs_ty = self.insert_type_vars_shallow(result);
let ty = match self.coerce(None, &expected, &lhs_ty, CoerceNever::Yes) {
Ok(ty) => ty,
Err(_) => {
self.result.type_mismatches.insert(
pat.into(),
TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() },
);
// `rhs_ty` is returned so no further type mismatches are
// reported because of this mismatch.
expected
}
};
self.write_pat_ty(pat, ty.clone());
self.inside_assignment = old_inside_assign;
return ty;
}
Pat::Missing => self.err_ty(),
};
@ -517,9 +545,12 @@ impl InferenceContext<'_> {
body[*expr],
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
),
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
false
}
Pat::Wild
| Pat::Bind { .. }
| Pat::Ref { .. }
| Pat::Box { .. }
| Pat::Missing
| Pat::Expr(_) => false,
}
}
}

View file

@ -94,8 +94,7 @@ impl InferenceContext<'_> {
return Some(ValuePathResolution::NonGeneric(ty));
};
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let substs = ctx.substs_from_path(path, value_def, true);
let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
let substs = substs.as_slice(Interner);
if let ValueNs::EnumVariantId(_) = value {
@ -152,8 +151,12 @@ impl InferenceContext<'_> {
let last = path.segments().last()?;
// Don't use `self.make_ty()` here as we need `orig_ns`.
let ctx =
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
&self.body.types,
self.owner.into(),
);
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
@ -164,9 +167,10 @@ impl InferenceContext<'_> {
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
let hygiene = self.body.expr_or_pat_path_hygiene(id);
// FIXME: report error, unresolved first path segment
let value_or_partial =
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?;
match value_or_partial {
ResolveValueResult::ValueNs(it, _) => (it, None),
@ -218,7 +222,7 @@ impl InferenceContext<'_> {
let _d;
let (resolved_segment, remaining_segments) = match path {
Path::Normal { .. } => {
Path::Normal { .. } | Path::BarePath(_) => {
assert!(remaining_index < path.segments().len());
(
path.segments().get(remaining_index - 1).unwrap(),
@ -242,17 +246,10 @@ impl InferenceContext<'_> {
(TypeNs::TraitId(trait_), true) => {
let segment =
remaining_segments.last().expect("there should be at least one segment here");
let ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
self.owner.into(),
);
let trait_ref = ctx.lower_trait_ref_from_resolved_path(
trait_,
resolved_segment,
self.table.new_type_var(),
);
let self_ty = self.table.new_type_var();
let trait_ref = self.with_body_ty_lowering(|ctx| {
ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
});
self.resolve_trait_assoc_item(trait_ref, segment, id)
}
(def, _) => {
@ -262,17 +259,14 @@ impl InferenceContext<'_> {
// as Iterator>::Item::default`)
let remaining_segments_for_ty =
remaining_segments.take(remaining_segments.len() - 1);
let ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
self.owner.into(),
);
let (ty, _) = ctx.lower_partly_resolved_path(
def,
resolved_segment,
remaining_segments_for_ty,
true,
);
let (ty, _) = self.with_body_ty_lowering(|ctx| {
ctx.lower_partly_resolved_path(
def,
resolved_segment,
remaining_segments_for_ty,
true,
)
});
if ty.is_unknown() {
return None;
}

View file

@ -917,9 +917,19 @@ impl<'a> InferenceTable<'a> {
/// Check if given type is `Sized` or not
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
// Early return for some obvious types
if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) {
if matches!(
ty.kind(Interner),
TyKind::Scalar(..)
| TyKind::Ref(..)
| TyKind::Raw(..)
| TyKind::Never
| TyKind::FnDef(..)
| TyKind::Array(..)
| TyKind::Function(_)
) {
return true;
}
if let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
let struct_data = self.db.struct_data(id);
if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() {

View file

@ -6,7 +6,7 @@ use base_db::ra_salsa::Cycle;
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{
layout::{
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData,
Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
},
LocalFieldId, StructId,
@ -66,24 +66,21 @@ impl rustc_index::Idx for RustcFieldIdx {
}
}
pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>;
pub type Layout = LayoutData<RustcFieldIdx, RustcEnumVariantIdx>;
pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LayoutError {
// FIXME: Remove variants that duplicate LayoutCalculatorError's variants after sync
// FIXME: Remove more variants once they get added to LayoutCalculatorError
BadCalc(LayoutCalculatorError<()>),
EmptyUnion,
HasErrorConst,
HasErrorType,
HasPlaceholder,
InvalidSimdType,
NotImplemented,
RecursiveTypeWithoutIndirection,
SizeOverflow,
TargetLayoutNotAvailable,
UnexpectedUnsized,
Unknown,
UserReprTooSmall,
}
@ -93,7 +90,6 @@ impl fmt::Display for LayoutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LayoutError::BadCalc(err) => err.fallback_fmt(f),
LayoutError::EmptyUnion => write!(f, "type is an union with no fields"),
LayoutError::HasErrorConst => write!(f, "type contains an unevaluatable const"),
LayoutError::HasErrorType => write!(f, "type contains an error"),
LayoutError::HasPlaceholder => write!(f, "type contains placeholders"),
@ -102,11 +98,7 @@ impl fmt::Display for LayoutError {
LayoutError::RecursiveTypeWithoutIndirection => {
write!(f, "recursive type without indirection")
}
LayoutError::SizeOverflow => write!(f, "size overflow"),
LayoutError::TargetLayoutNotAvailable => write!(f, "target layout not available"),
LayoutError::UnexpectedUnsized => {
write!(f, "an unsized type was found where a sized type was expected")
}
LayoutError::Unknown => write!(f, "unknown"),
LayoutError::UserReprTooSmall => {
write!(f, "the `#[repr]` hint is too small to hold the discriminants of the enum")
@ -181,7 +173,10 @@ fn layout_of_simd_ty(
};
// Compute the size and alignment of the vector:
let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow)?;
let size = e_ly
.size
.checked_mul(e_len, dl)
.ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
let align = dl.vector_align(size);
let size = size.align_to(align.abi);
@ -294,7 +289,10 @@ pub fn layout_of_ty_query(
TyKind::Array(element, count) => {
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
let element = db.layout_of_ty(element.clone(), trait_env)?;
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
let size = element
.size
.checked_mul(count, dl)
.ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
Abi::Uninhabited

View file

@ -51,10 +51,7 @@ mod test_db;
#[cfg(test)]
mod tests;
use std::{
collections::hash_map::Entry,
hash::{BuildHasherDefault, Hash},
};
use std::hash::Hash;
use base_db::ra_salsa::InternValueTrivial;
use chalk_ir::{
@ -65,10 +62,11 @@ use chalk_ir::{
use either::Either;
use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId};
use hir_expand::name::Name;
use indexmap::{map::Entry, IndexMap};
use intern::{sym, Symbol};
use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use span::Edition;
use syntax::ast::{make, ConstArg};
use traits::FnTrait;
@ -199,7 +197,7 @@ pub enum MemoryMap {
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ComplexMemoryMap {
memory: FxHashMap<usize, Box<[u8]>>,
memory: IndexMap<usize, Box<[u8]>, FxBuildHasher>,
vtable: VTableMap,
}
@ -245,7 +243,7 @@ impl MemoryMap {
match self {
MemoryMap::Empty => Ok(Default::default()),
MemoryMap::Simple(m) => transform((&0, m)).map(|(addr, val)| {
let mut map = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());
let mut map = FxHashMap::with_capacity_and_hasher(1, rustc_hash::FxBuildHasher);
map.insert(addr, val);
map
}),

View file

@ -34,6 +34,7 @@ use hir_def::{
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
type_ref::{
ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
TypeRefId, TypesMap, TypesSourceMap,
},
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@ -41,7 +42,6 @@ use hir_def::{
TypeOwnerId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
use intern::Interned;
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::Captures;
@ -122,6 +122,11 @@ pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
resolver: &'a Resolver,
generics: OnceCell<Option<Generics>>,
types_map: &'a TypesMap,
/// If this is set, that means we're in a context of a freshly expanded macro, and that means
/// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`,
/// instead we need to put `TypeSource` from the source map.
types_source_map: Option<&'a TypesSourceMap>,
in_binders: DebruijnIndex,
// FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
// where expected
@ -138,13 +143,20 @@ pub struct TyLoweringContext<'a> {
}
impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
Self::new_maybe_unowned(db, resolver, Some(owner))
pub fn new(
db: &'a dyn HirDatabase,
resolver: &'a Resolver,
types_map: &'a TypesMap,
owner: TypeOwnerId,
) -> Self {
Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner))
}
pub fn new_maybe_unowned(
db: &'a dyn HirDatabase,
resolver: &'a Resolver,
types_map: &'a TypesMap,
types_source_map: Option<&'a TypesSourceMap>,
owner: Option<TypeOwnerId>,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::Disallowed;
@ -154,6 +166,8 @@ impl<'a> TyLoweringContext<'a> {
db,
resolver,
generics: OnceCell::new(),
types_map,
types_source_map,
owner,
in_binders,
impl_trait_mode,
@ -201,6 +215,16 @@ impl<'a> TyLoweringContext<'a> {
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
Self { type_param_mode, ..self }
}
pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
self
}
pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
self.type_param_mode = type_param_mode;
self
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -230,7 +254,7 @@ pub enum ParamLoweringMode {
}
impl<'a> TyLoweringContext<'a> {
pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty {
self.lower_ty_ext(type_ref).0
}
@ -254,12 +278,13 @@ impl<'a> TyLoweringContext<'a> {
.as_ref()
}
pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
let mut res = None;
let type_ref = &self.types_map[type_ref_id];
let ty = match type_ref {
TypeRef::Never => TyKind::Never.intern(Interner),
TypeRef::Tuple(inner) => {
let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner)
}
@ -268,38 +293,43 @@ impl<'a> TyLoweringContext<'a> {
res = res_;
ty
}
TypeRef::RawPtr(inner, mutability) => {
&TypeRef::RawPtr(inner, mutability) => {
let inner_ty = self.lower_ty(inner);
TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
}
TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner);
let const_len = self.lower_const(len, TyBuilder::usize());
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)
}
TypeRef::Slice(inner) => {
&TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner);
TyKind::Slice(inner_ty).intern(Interner)
}
TypeRef::Reference(inner, lifetime, mutability) => {
let inner_ty = self.lower_ty(inner);
TypeRef::Reference(ref_) => {
let inner_ty = self.lower_ty(ref_.ty);
// FIXME: It should infer the eldided lifetimes instead of stubbing with static
let lifetime =
lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
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)
}
TypeRef::Placeholder => TyKind::Error.intern(Interner),
&TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => {
TypeRef::Fn(fn_) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
Substitution::from_iter(
Interner,
fn_.params().iter().map(|&(_, tr)| ctx.lower_ty(tr)),
)
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
sig: FnSig {
abi: abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
variadic,
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),
})
@ -351,8 +381,8 @@ impl<'a> TyLoweringContext<'a> {
ImplTraitLoweringState::Param(counter) => {
let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16);
// Since those have been emitted as implicit type args already.
counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self
.generics()
.expect("param impl trait lowering must be in a generic def")
@ -376,7 +406,7 @@ impl<'a> TyLoweringContext<'a> {
let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16);
counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self
.generics()
.expect("variable impl trait lowering must be in a generic def")
@ -432,12 +462,40 @@ impl<'a> TyLoweringContext<'a> {
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
{
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
let ctx = expander.ctx(self.db.upcast());
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = expander.ctx(
self.db.upcast(),
&mut types_map,
&mut types_source_map,
);
// FIXME: Report syntax errors in expansion here
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
drop(expander);
let ty = self.lower_ty(&type_ref);
// FIXME: That may be better served by mutating `self` then restoring, but this requires
// making it `&mut self`.
let inner_ctx = TyLoweringContext {
db: self.db,
resolver: self.resolver,
generics: self.generics.clone(),
types_map: &types_map,
types_source_map: Some(&types_source_map),
in_binders: self.in_binders,
owner: self.owner,
type_param_mode: self.type_param_mode,
impl_trait_mode: self.impl_trait_mode.take(),
expander: RefCell::new(self.expander.take()),
unsized_types: RefCell::new(self.unsized_types.take()),
};
let ty = inner_ctx.lower_ty(type_ref);
self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode);
*self.expander.borrow_mut() = inner_ctx.expander.into_inner();
*self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner();
self.expander.borrow_mut().as_mut().unwrap().exit(mark);
Some(ty)
@ -463,7 +521,8 @@ impl<'a> TyLoweringContext<'a> {
/// 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: &TypeRef) -> Option<TypeOrConstParamId> {
fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
let type_ref = &self.types_map[type_ref];
let path = match type_ref {
TypeRef::Path(path) => path,
_ => return None,
@ -663,7 +722,7 @@ impl<'a> TyLoweringContext<'a> {
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
// trait object type without dyn
let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
let ty = self.lower_dyn_trait(&[bound]);
return (ty, None);
}
@ -864,7 +923,7 @@ impl<'a> TyLoweringContext<'a> {
assert!(matches!(id, GenericParamId::TypeParamId(_)));
had_explicit_args = true;
if let GenericArg::Type(ty) = &args[0] {
substs.push(self.lower_ty(ty).cast(Interner));
substs.push(self.lower_ty(*ty).cast(Interner));
}
}
} else {
@ -901,6 +960,7 @@ impl<'a> TyLoweringContext<'a> {
id,
arg,
&mut (),
self.types_map,
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
@ -998,7 +1058,7 @@ impl<'a> TyLoweringContext<'a> {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
let self_ty = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
match self.type_param_mode {
@ -1029,12 +1089,12 @@ impl<'a> TyLoweringContext<'a> {
pub(crate) fn lower_type_bound(
&'a self,
bound: &'a Interned<TypeBound>,
bound: &'a TypeBound,
self_ty: Ty,
ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let mut trait_ref = None;
let clause = match bound.as_ref() {
let clause = match bound {
TypeBound::Path(path, TraitBoundModifier::None) => {
trait_ref = self.lower_trait_ref_from_path(path, self_ty);
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@ -1067,7 +1127,7 @@ impl<'a> TyLoweringContext<'a> {
lifetime,
})))
}
TypeBound::Error => None,
TypeBound::Use(_) | TypeBound::Error => None,
};
clause.into_iter().chain(
trait_ref
@ -1079,14 +1139,15 @@ impl<'a> TyLoweringContext<'a> {
fn assoc_type_bindings_from_type_bound(
&'a self,
bound: &'a Interned<TypeBound>,
bound: &'a TypeBound,
trait_ref: TraitRef,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let last_segment = match bound.as_ref() {
let last_segment = match bound {
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
path.segments().last()
}
TypeBound::Path(_, TraitBoundModifier::Maybe)
| TypeBound::Use(_)
| TypeBound::Error
| TypeBound::Lifetime(_) => None,
};
@ -1110,7 +1171,7 @@ impl<'a> TyLoweringContext<'a> {
// this point (`super_trait_ref.substitution`).
let substitution = self.substs_from_path_segment(
// FIXME: This is hack. We shouldn't really build `PathSegment` directly.
PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
Some(associated_ty.into()),
false, // this is not relevant
Some(super_trait_ref.self_type_parameter(Interner)),
@ -1130,8 +1191,8 @@ impl<'a> TyLoweringContext<'a> {
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 {
match (type_ref, &self.impl_trait_mode) {
if let Some(type_ref) = binding.type_ref {
match (&self.types_map[type_ref], &self.impl_trait_mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
(
_,
@ -1178,6 +1239,8 @@ impl<'a> TyLoweringContext<'a> {
let mut ext = TyLoweringContext::new_maybe_unowned(
self.db,
self.resolver,
self.types_map,
self.types_source_map,
self.owner,
)
.with_type_param_mode(self.type_param_mode);
@ -1215,7 +1278,7 @@ impl<'a> TyLoweringContext<'a> {
})
}
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
// 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
@ -1313,7 +1376,7 @@ impl<'a> TyLoweringContext<'a> {
}
}
fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait {
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| {
@ -1365,6 +1428,17 @@ impl<'a> TyLoweringContext<'a> {
None => error_lifetime(),
}
}
// FIXME: This does not handle macros!
fn count_impl_traits(&self, type_ref: TypeRefId) -> usize {
let mut count = 0;
TypeRef::walk(type_ref, self.types_map, &mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
}
/// Build the signature of a callable item (function, struct or enum variant).
@ -1385,17 +1459,6 @@ pub fn associated_type_shorthand_candidates<R>(
named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
}
// FIXME: This does not handle macros!
fn count_impl_traits(type_ref: &TypeRef) -> usize {
let mut count = 0;
type_ref.walk(&mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
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
@ -1499,10 +1562,10 @@ pub(crate) fn field_types_query(
};
let generics = generics(db.upcast(), def);
let mut res = ArenaMap::default();
let ctx = TyLoweringContext::new(db, &resolver, def.into())
let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into())
.with_type_param_mode(ParamLoweringMode::Variable);
for (field_id, field_data) in var_data.fields().iter() {
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
}
Arc::new(res)
}
@ -1522,38 +1585,38 @@ pub(crate) fn generic_predicates_for_param_query(
assoc_name: Option<Name>,
) -> GenericPredicates {
let resolver = def.resolver(db.upcast());
let ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, def.into())
let mut ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable)
} else {
TyLoweringContext::new(db, &resolver, def.into())
TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Variable)
};
let generics = generics(db.upcast(), def);
// we have to filter out all other predicates *first*, before attempting to lower them
let predicate = |(pred, &def): &(&_, _)| match pred {
let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => {
ctx.lower_ty_only_param(type_ref) != Some(param_id)
ctx.lower_ty_only_param(*type_ref) != Some(param_id)
}
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let target_id = TypeOrConstParamId { parent: def, local_id };
let target_id = TypeOrConstParamId { parent: *def, local_id };
target_id != param_id
}
};
if invalid_target {
// If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound {
ctx.lower_where_predicate(pred, &def, true).for_each(drop);
if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
ctx.lower_where_predicate(pred, def, true).for_each(drop);
}
return false;
}
match &**bound {
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.
@ -1571,18 +1634,20 @@ pub(crate) fn generic_predicates_for_param_query(
})
})
}
TypeBound::Lifetime(_) | TypeBound::Error => false,
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
}
}
WherePredicate::Lifetime { .. } => false,
};
let mut predicates: Vec<_> = resolver
.where_predicates_in_scope()
.filter(predicate)
.flat_map(|(pred, def)| {
ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
})
.collect();
let mut predicates = Vec::new();
for (params, def) in resolver.all_generic_params() {
ctx.types_map = &params.types_map;
predicates.extend(
params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| {
ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
}),
);
}
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
if !subst.is_empty(Interner) {
@ -1629,23 +1694,27 @@ pub(crate) fn trait_environment_query(
def: GenericDefId,
) -> Arc<TraitEnvironment> {
let resolver = def.resolver(db.upcast());
let ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, def.into())
let mut ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Param)
.with_type_param_mode(ParamLoweringMode::Placeholder)
} else {
TyLoweringContext::new(db, &resolver, def.into())
TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Placeholder)
};
let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new();
for (pred, def) in resolver.where_predicates_in_scope() {
for pred in ctx.lower_where_predicate(pred, def, false) {
if let WhereClause::Implemented(tr) = &pred.skip_binders() {
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
for (params, def) in resolver.all_generic_params() {
ctx.types_map = &params.types_map;
for pred in params.where_predicates() {
for pred in ctx.lower_where_predicate(pred, def, false) {
if let WhereClause::Implemented(tr) = pred.skip_binders() {
traits_in_scope
.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
}
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
clauses.push(program_clause.into_from_env_clause(Interner));
}
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
clauses.push(program_clause.into_from_env_clause(Interner));
}
}
@ -1724,18 +1793,20 @@ where
}
_ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
};
let ctx = TyLoweringContext::new(db, &resolver, def.into())
let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(impl_trait_lowering)
.with_type_param_mode(param_lowering);
let generics = generics(db.upcast(), def);
let mut predicates = resolver
.where_predicates_in_scope()
.filter(|(pred, def)| filter(pred, def))
.flat_map(|(pred, def)| {
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
})
.collect::<Vec<_>>();
let mut predicates = Vec::new();
for (params, def) in resolver.all_generic_params() {
ctx.types_map = &params.types_map;
predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map(
|pred| {
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
},
));
}
if generics.len() > 0 {
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@ -1811,18 +1882,19 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self();
let ctx = TyLoweringContext::new(db, &resolver, def.into())
let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
.with_type_param_mode(ParamLoweringMode::Variable);
GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
|(idx, (id, p))| {
GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
|(idx, ((id, p), types_map))| {
ctx.types_map = types_map;
match p {
GenericParamDataRef::TypeParamData(p) => {
let ty = p.default.as_ref().map_or(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, parent_start_idx)
fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
});
crate::make_binders(db, &generic_params, ty.cast(Interner))
}
@ -1834,7 +1906,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
let mut val = p.default.as_ref().map_or_else(
|| unknown_const_as_generic(db.const_param_ty(id)),
|c| {
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
let c = ctx.lower_const(c, ctx.lower_ty(p.ty));
c.cast(Interner)
},
);
@ -1874,14 +1946,14 @@ pub(crate) fn generic_defaults_recover(
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let data = db.function_data(def);
let resolver = def.resolver(db.upcast());
let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable);
let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
let ret = ctx_ret.lower_ty(&data.ret_type);
let ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into());
let sig = CallableSig::from_params_and_return(
params,
@ -1910,28 +1982,33 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
let data = db.const_data(def);
let generics = generics(db.upcast(), def.into());
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into())
let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_type_param_mode(ParamLoweringMode::Variable);
make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
make_binders(db, &generics, ctx.lower_ty(data.type_ref))
}
/// Build the declared type of a static.
fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
let data = db.static_data(def);
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into());
let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into());
Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
Binders::empty(Interner, ctx.lower_ty(data.type_ref))
}
fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
let struct_data = db.struct_data(def);
let fields = struct_data.variant_data.fields();
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
.with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
let ctx = TyLoweringContext::new(
db,
&resolver,
struct_data.variant_data.types_map(),
AdtId::from(def).into(),
)
.with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
Binders::new(
binders,
@ -1961,9 +2038,14 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
let var_data = db.enum_variant_data(def);
let fields = var_data.variant_data.fields();
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
.with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
let ctx = TyLoweringContext::new(
db,
&resolver,
var_data.variant_data.types_map(),
DefWithBodyId::VariantId(def).into(),
)
.with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) =
type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
Binders::new(
@ -2004,15 +2086,17 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, t.into())
let type_alias_data = db.type_alias_data(t);
let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
let type_alias_data = db.type_alias_data(t);
let inner = if type_alias_data.is_extern {
TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
} else {
let type_ref = &type_alias_data.type_ref;
ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error))
type_alias_data
.type_ref
.map(|type_ref| ctx.lower_ty(type_ref))
.unwrap_or_else(|| TyKind::Error.intern(Interner))
};
make_binders(db, &generics, inner)
}
@ -2085,9 +2169,9 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let generics = generics(db.upcast(), impl_id.into());
let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable);
make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
}
// returns None if def is a type arg
@ -2095,13 +2179,13 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T
let parent_data = db.generic_params(def.parent());
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.parent().into());
let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
Ty::new(Interner, TyKind::Error)
}
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
}
}
@ -2117,7 +2201,7 @@ pub(crate) fn impl_self_ty_recover(
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?;
@ -2131,10 +2215,10 @@ pub(crate) fn return_type_impl_traits(
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
let data = db.function_data(def);
let resolver = def.resolver(db.upcast());
let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
let _ret = ctx_ret.lower_ty(&data.ret_type);
let _ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into());
let return_type_impl_traits = ImplTraits {
impl_traits: match ctx_ret.impl_trait_mode {
@ -2155,10 +2239,10 @@ pub(crate) fn type_alias_impl_traits(
) -> Option<Arc<Binders<ImplTraits>>> {
let data = db.type_alias_data(def);
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into())
let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
if let Some(type_ref) = &data.type_ref {
if let Some(type_ref) = data.type_ref {
let _ty = ctx.lower_ty(type_ref);
}
let type_alias_impl_traits = ImplTraits {
@ -2190,7 +2274,8 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
kind_id: GenericParamId,
arg: &'a GenericArg,
this: &mut T,
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
types_map: &TypesMap,
for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
) -> crate::GenericArg {
@ -2203,7 +2288,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
};
match (arg, kind) {
(GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
(GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
(GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
(GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
for_lifetime(this, lifetime_ref).cast(Interner)
@ -2214,7 +2299,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
// We want to recover simple idents, which parser detects them
// as types. Maybe here is not the best place to do it, but
// it works.
if let TypeRef::Path(p) = t {
if let TypeRef::Path(p) = &types_map[*t] {
if let Some(p) = p.mod_path() {
if p.kind == PathKind::Plain {
if let [n] = p.segments() {

View file

@ -879,7 +879,8 @@ pub enum Rvalue {
///
/// **Needs clarification**: Are there weird additional semantics here related to the runtime
/// nature of this operation?
//ThreadLocalRef(DefId),
// ThreadLocalRef(DefId),
ThreadLocalRef(std::convert::Infallible),
/// Creates a pointer with the indicated mutability to the place.
///
@ -888,7 +889,8 @@ pub enum Rvalue {
///
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
/// model.
//AddressOf(Mutability, Place),
// AddressOf(Mutability, Place),
AddressOf(std::convert::Infallible),
/// Yields the length of the place, as a `usize`.
///
@ -906,19 +908,21 @@ pub enum Rvalue {
Cast(CastKind, Operand, Ty),
// FIXME link to `pointer::offset` when it hits stable.
// /// * `Offset` has the same semantics as `pointer::offset`, except that the second
// /// parameter may be a `usize` as well.
// /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
// /// raw pointers, or function pointers and return a `bool`. The types of the operands must be
// /// matching, up to the usual caveat of the lifetimes in function pointers.
// /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
// /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
// /// truncated as needed.
// /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
// /// types and return a value of that type.
// /// * The remaining operations accept signed integers, unsigned integers, or floats with
// /// matching types and return a value of that type.
/// * `Offset` has the same semantics as `pointer::offset`, except that the second
/// parameter may be a `usize` as well.
/// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
/// raw pointers, or function pointers and return a `bool`. The types of the operands must be
/// matching, up to the usual caveat of the lifetimes in function pointers.
/// * Left and right shift operations accept signed or unsigned integers not necessarily of the
/// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
/// truncated as needed.
/// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
/// types and return a value of that type.
/// * The remaining operations accept signed integers, unsigned integers, or floats with
/// matching types and return a value of that type.
//BinaryOp(BinOp, Box<(Operand, Operand)>),
BinaryOp(std::convert::Infallible),
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
///
/// When overflow checking is disabled and we are generating run-time code, the error condition
@ -937,6 +941,7 @@ pub enum Rvalue {
/// Computes a value as described by the operation.
//NullaryOp(NullOp, Ty),
NullaryOp(std::convert::Infallible),
/// Exactly like `BinaryOp`, but less operands.
///
@ -1095,6 +1100,10 @@ impl MirBody {
for_operand(op, &mut f, &mut self.projection_store);
}
}
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
}
}
StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {

View file

@ -167,6 +167,10 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
for_operand(op, statement.span);
}
}
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::FakeRead(_)
| StatementKind::Deinit(_)
@ -253,6 +257,10 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved>
for_operand(op, statement.span);
}
}
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::FakeRead(_)
| StatementKind::Deinit(_)
@ -548,6 +556,10 @@ fn mutability_of_locals(
}
}
Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
}
if let Rvalue::Ref(
BorrowKind::Mut {

View file

@ -6,6 +6,7 @@ use base_db::CrateId;
use chalk_ir::{cast::Cast, Mutability};
use either::Either;
use hir_def::{
body::HygieneId,
builtin_type::BuiltinType,
data::adt::{StructFlags, VariantData},
lang_item::LangItem,
@ -1628,6 +1629,10 @@ impl Evaluator<'_> {
}
CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
},
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
})
}
@ -2703,17 +2708,15 @@ impl Evaluator<'_> {
TyKind::Function(_) => {
self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span)
}
TyKind::Closure(closure, subst) => {
return self.exec_closure(
*closure,
func_data,
&Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
destination,
&args[1..],
locals,
span,
);
}
TyKind::Closure(closure, subst) => self.exec_closure(
*closure,
func_data,
&Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
destination,
&args[1..],
locals,
span,
),
_ => {
// try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
let arg0 = func;
@ -2846,7 +2849,8 @@ impl Evaluator<'_> {
}
let layout = self.layout_adt(id.0, subst.clone())?;
match data.variant_data.as_ref() {
VariantData::Record(fields) | VariantData::Tuple(fields) => {
VariantData::Record { fields, .. }
| VariantData::Tuple { fields, .. } => {
let field_types = self.db.field_types(s.into());
for (field, _) in fields.iter() {
let offset = layout
@ -2951,6 +2955,7 @@ pub fn render_const_using_debug_impl(
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
HygieneId::ROOT,
) else {
not_supported!("std::fmt::format not found");
};

View file

@ -5,7 +5,7 @@ use std::{fmt::Write, iter, mem};
use base_db::ra_salsa::Cycle;
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
body::Body,
body::{Body, HygieneId},
data::adt::{StructKind, VariantData},
hir::{
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
@ -13,7 +13,8 @@ use hir_def::{
},
lang_item::{LangItem, LangItemTarget},
path::Path,
resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
type_ref::TypesMap,
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
Lookup, TraitId, TupleId, TypeOrConstParamId,
};
@ -28,7 +29,7 @@ use triomphe::Arc;
use crate::{
consteval::ConstEvalError,
db::{HirDatabase, InternedClosure},
display::HirDisplay,
display::{hir_display_with_types_map, HirDisplay},
error_lifetime,
generics::generics,
infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@ -76,6 +77,7 @@ struct MirLowerCtx<'a> {
db: &'a dyn HirDatabase,
body: &'a Body,
infer: &'a InferenceResult,
resolver: Resolver,
drop_scopes: Vec<DropScope>,
}
@ -246,8 +248,15 @@ impl From<LayoutError> for MirLowerError {
}
impl MirLowerError {
fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
Self::UnresolvedName(p.display(db, edition).to_string())
fn unresolved_path(
db: &dyn HirDatabase,
p: &Path,
edition: Edition,
types_map: &TypesMap,
) -> Self {
Self::UnresolvedName(
hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
)
}
}
@ -278,6 +287,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
owner,
closures: vec![],
};
let resolver = owner.resolver(db.upcast());
MirLowerCtx {
result: mir,
@ -285,6 +295,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
infer,
body,
owner,
resolver,
current_loop_blocks: None,
labeled_loop_blocks: Default::default(),
discr_temp: None,
@ -410,43 +421,54 @@ impl<'ctx> MirLowerCtx<'ctx> {
Err(MirLowerError::IncompleteExpr)
}
Expr::Path(p) => {
let pr =
if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) {
match assoc {
hir_def::AssocItemId::ConstId(c) => {
self.lower_const(
c.into(),
current,
place,
subst,
expr_id.into(),
self.expr_ty_without_adjust(expr_id),
)?;
return Ok(Some(current));
}
hir_def::AssocItemId::FunctionId(_) => {
// FnDefs are zero sized, no action is needed.
return Ok(Some(current));
}
hir_def::AssocItemId::TypeAliasId(_) => {
// FIXME: If it is unreachable, use proper error instead of `not_supported`.
not_supported!("associated functions and types")
}
let pr = if let Some((assoc, subst)) =
self.infer.assoc_resolutions_for_expr(expr_id)
{
match assoc {
hir_def::AssocItemId::ConstId(c) => {
self.lower_const(
c.into(),
current,
place,
subst,
expr_id.into(),
self.expr_ty_without_adjust(expr_id),
)?;
return Ok(Some(current));
}
} else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
match variant {
VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
VariantId::StructId(s) => ValueNs::StructId(s),
VariantId::UnionId(_) => implementation_error!("Union variant as path"),
hir_def::AssocItemId::FunctionId(_) => {
// FnDefs are zero sized, no action is needed.
return Ok(Some(current));
}
} else {
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, p, self.edition());
let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), p)
.ok_or_else(unresolved_name)?
};
hir_def::AssocItemId::TypeAliasId(_) => {
// FIXME: If it is unreachable, use proper error instead of `not_supported`.
not_supported!("associated functions and types")
}
}
} else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
match variant {
VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
VariantId::StructId(s) => ValueNs::StructId(s),
VariantId::UnionId(_) => implementation_error!("Union variant as path"),
}
} else {
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
let hygiene = self.body.expr_path_hygiene(expr_id);
let result = self
.resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene)
.ok_or_else(|| {
MirLowerError::unresolved_path(
self.db,
p,
self.edition(),
&self.body.types,
)
})?;
self.resolver.reset_to_guard(resolver_guard);
result
};
match pr {
ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => {
let Some((temp, current)) =
@ -553,8 +575,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
self.push_fake_read(current, cond_place, expr_id.into());
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
let (then_target, else_target) =
self.pattern_match(current, None, cond_place, *pat)?;
self.resolver.reset_to_guard(resolver_guard);
self.write_bytes_to_place(
then_target,
place,
@ -688,6 +713,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
self.push_fake_read(current, cond_place, expr_id.into());
let mut end = None;
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) =
self.pattern_match(current, None, cond_place, *pat)?;
@ -721,6 +748,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
}
self.resolver.reset_to_guard(resolver_guard);
if self.is_unterminated(current) {
self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into());
}
@ -795,7 +823,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
Expr::Become { .. } => not_supported!("tail-calls"),
Expr::Yield { .. } => not_supported!("yield"),
Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
Expr::RecordLit { fields, path, spread } => {
let spread_place = match spread {
&Some(it) => {
let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {
@ -809,7 +837,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
let variant_id =
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName(
p.display(self.db, self.edition()).to_string(),
hir_display_with_types_map(&**p, &self.body.types)
.display(self.db, self.edition())
.to_string(),
),
None => MirLowerError::RecordLiteralWithoutPath,
})?;
@ -1010,35 +1040,28 @@ impl<'ctx> MirLowerCtx<'ctx> {
);
}
}
if let hir_def::hir::BinaryOp::Assignment { op } = op {
if let Some(op) = op {
// last adjustment is `&mut` which we don't want it.
let adjusts = self
.infer
.expr_adjustments
.get(lhs)
.and_then(|it| it.split_last())
.map(|it| it.1)
.ok_or(MirLowerError::TypeError(
"adjustment of binary op was missing",
))?;
let Some((lhs_place, current)) =
self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
else {
return Ok(None);
};
let Some((rhs_op, current)) =
self.lower_expr_to_some_operand(*rhs, current)?
else {
return Ok(None);
};
let r_value =
Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
self.push_assignment(current, lhs_place, r_value, expr_id.into());
return Ok(Some(current));
} else {
return self.lower_assignment(current, *lhs, *rhs, expr_id.into());
}
if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {
// last adjustment is `&mut` which we don't want it.
let adjusts = self
.infer
.expr_adjustments
.get(lhs)
.and_then(|it| it.split_last())
.map(|it| it.1)
.ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?;
let Some((lhs_place, current)) =
self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
else {
return Ok(None);
};
let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?
else {
return Ok(None);
};
let r_value =
Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
self.push_assignment(current, lhs_place, r_value, expr_id.into());
return Ok(Some(current));
}
let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?
else {
@ -1097,6 +1120,18 @@ impl<'ctx> MirLowerCtx<'ctx> {
);
Ok(Some(current))
}
&Expr::Assignment { target, value } => {
let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)?
else {
return Ok(None);
};
self.push_fake_read(current, value, expr_id.into());
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
current = self.pattern_match_assignment(current, value, target)?;
self.resolver.reset_to_guard(resolver_guard);
Ok(Some(current))
}
&Expr::Range { lhs, rhs, range_type: _ } => {
let ty = self.expr_ty_without_adjust(expr_id);
let Some((adt, subst)) = ty.as_adt() else {
@ -1213,7 +1248,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
);
Ok(Some(current))
}
Expr::Tuple { exprs, is_assignee_expr: _ } => {
Expr::Tuple { exprs } => {
let Some(values) = exprs
.iter()
.map(|it| {
@ -1291,73 +1326,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
fn lower_destructing_assignment(
&mut self,
mut current: BasicBlockId,
lhs: ExprId,
rhs: Place,
span: MirSpan,
) -> Result<Option<BasicBlockId>> {
match &self.body.exprs[lhs] {
Expr::Tuple { exprs, is_assignee_expr: _ } => {
for (i, expr) in exprs.iter().enumerate() {
let rhs = rhs.project(
ProjectionElem::Field(Either::Right(TupleFieldId {
tuple: TupleId(!0), // Dummy this as its unused
index: i as u32,
})),
&mut self.result.projection_store,
);
let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
else {
return Ok(None);
};
current = c;
}
Ok(Some(current))
}
Expr::Underscore => Ok(Some(current)),
_ => {
let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
else {
return Ok(None);
};
self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
Ok(Some(current))
}
}
}
fn lower_assignment(
&mut self,
current: BasicBlockId,
lhs: ExprId,
rhs: ExprId,
span: MirSpan,
) -> Result<Option<BasicBlockId>> {
let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else {
return Ok(None);
};
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
self.push_fake_read_for_operand(current, rhs_op, span);
return Ok(Some(current));
}
if matches!(
&self.body.exprs[lhs],
Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
) {
let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
let temp = Place::from(temp);
self.push_assignment(current, temp, rhs_op.into(), span);
return self.lower_destructing_assignment(current, lhs, temp, span);
}
let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else {
return Ok(None);
};
self.push_assignment(current, lhs_place, rhs_op.into(), span);
Ok(Some(current))
}
fn placeholder_subst(&mut self) -> Substitution {
match self.owner.as_generic_def_id(self.db.upcast()) {
Some(it) => TyBuilder::placeholder_subst(self.db, it),
@ -1406,10 +1374,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
let edition = self.edition();
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
let resolver = self.owner.resolver(self.db.upcast());
let pr = resolver
.resolve_path_in_value_ns(self.db.upcast(), c.as_ref())
|| MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
let pr = self
.resolver
.resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
.ok_or_else(unresolved_name)?;
match pr {
ResolveValueResult::ValueNs(v, _) => {
@ -1632,12 +1600,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.push_statement(block, StatementKind::FakeRead(p).with_span(span));
}
fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) {
if let Operand::Move(p) | Operand::Copy(p) = operand {
self.push_fake_read(block, p, span);
}
}
fn push_assignment(
&mut self,
block: BasicBlockId,
@ -1791,8 +1753,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
current = c;
self.push_fake_read(current, init_place, span);
// Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations
// and has all declarations of the `let`.
let resolver_guard = self.resolver.update_to_inner_scope(
self.db.upcast(),
self.owner,
*expr_id,
);
(current, else_block) =
self.pattern_match(current, None, init_place, *pat)?;
self.resolver.reset_to_guard(resolver_guard);
match (else_block, else_branch) {
(None, _) => (),
(Some(else_block), None) => {
@ -1828,7 +1798,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.push_fake_read(c, p, expr.into());
current = scope2.pop_and_drop(self, c, expr.into());
}
hir_def::hir::Statement::Item => (),
hir_def::hir::Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
@ -2066,11 +2036,13 @@ pub fn mir_body_for_closure_query(
let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else {
implementation_error!("closure has not callable sig");
};
let resolver_guard = ctx.resolver.update_to_inner_scope(db.upcast(), owner, expr);
let current = ctx.lower_params_and_bindings(
args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())),
None,
|_| true,
)?;
ctx.resolver.reset_to_guard(resolver_guard);
if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
ctx.set_terminator(current, TerminatorKind::Return, (*root).into());

View file

@ -135,8 +135,13 @@ impl MirLowerCtx<'_> {
};
match &self.body.exprs[expr_id] {
Expr::Path(p) => {
let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else {
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
let hygiene = self.body.expr_path_hygiene(expr_id);
let resolved =
self.resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene);
self.resolver.reset_to_guard(resolver_guard);
let Some(pr) = resolved else {
return try_rvalue(self);
};
match pr {
@ -216,7 +221,7 @@ impl MirLowerCtx<'_> {
self.push_field_projection(&mut r, expr_id)?;
Ok(Some((r, current)))
}
Expr::Index { base, index, is_assignee_expr: _ } => {
Expr::Index { base, index } => {
let base_ty = self.expr_ty_after_adjustments(*base);
let index_ty = self.expr_ty_after_adjustments(*index);
if index_ty != TyBuilder::usize()

View file

@ -1,6 +1,6 @@
//! MIR lowering for patterns
use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
use hir_def::{hir::LiteralOrConst, AssocItemId};
use crate::{
mir::{
@ -46,6 +46,8 @@ enum MatchingMode {
Check,
/// Assume that this pattern matches, fill bindings
Bind,
/// Assume that this pattern matches, assign to existing variables.
Assign,
}
impl MirLowerCtx<'_> {
@ -82,6 +84,17 @@ impl MirLowerCtx<'_> {
Ok((current, current_else))
}
pub(super) fn pattern_match_assignment(
&mut self,
current: BasicBlockId,
value: Place,
pattern: PatId,
) -> Result<BasicBlockId> {
let (current, _) =
self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?;
Ok(current)
}
pub(super) fn match_self_param(
&mut self,
id: BindingId,
@ -155,14 +168,8 @@ impl MirLowerCtx<'_> {
*pat,
MatchingMode::Check,
)?;
if mode == MatchingMode::Bind {
(next, _) = self.pattern_match_inner(
next,
None,
cond_place,
*pat,
MatchingMode::Bind,
)?;
if mode != MatchingMode::Check {
(next, _) = self.pattern_match_inner(next, None, cond_place, *pat, mode)?;
}
self.set_goto(next, then_target, pattern.into());
match next_else {
@ -176,11 +183,11 @@ impl MirLowerCtx<'_> {
}
}
if !finished {
if mode == MatchingMode::Bind {
self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
} else {
if mode == MatchingMode::Check {
let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
self.set_goto(current, ce, pattern.into());
} else {
self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
}
}
(then_target, current_else)
@ -300,7 +307,7 @@ impl MirLowerCtx<'_> {
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let &Some(slice) = slice {
if mode == MatchingMode::Bind {
if mode != MatchingMode::Check {
if let Pat::Bind { id, subpat: _ } = self.body[slice] {
let next_place = cond_place.project(
ProjectionElem::Subslice {
@ -342,17 +349,36 @@ impl MirLowerCtx<'_> {
mode,
)?,
None => {
// The path is not a variant, so it is a const
let unresolved_name = || {
MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
};
let hygiene = self.body.pat_path_hygiene(pattern);
let pr = self
.resolver
.resolve_path_in_value_ns(self.db.upcast(), p, hygiene)
.ok_or_else(unresolved_name)?;
if let (
MatchingMode::Assign,
ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _),
) = (mode, &pr)
{
let local = self.binding_local(*binding)?;
self.push_match_assignment(
current,
local,
BindingMode::Move,
cond_place,
pattern.into(),
);
return Ok((current, current_else));
}
// The path is not a variant or a local, so it is a const
if mode != MatchingMode::Check {
// A const don't bind anything. Only needs check.
return Ok((current, current_else));
}
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, p, self.edition());
let resolver = self.owner.resolver(self.db.upcast());
let pr = resolver
.resolve_path_in_value_ns(self.db.upcast(), p)
.ok_or_else(unresolved_name)?;
let (c, subst) = 'b: {
if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) {
if let AssocItemId::ConstId(c) = x.0 {
@ -415,7 +441,7 @@ impl MirLowerCtx<'_> {
(current, current_else) =
self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)?
}
if mode == MatchingMode::Bind {
if mode != MatchingMode::Check {
let mode = self.infer.binding_modes[pattern];
self.pattern_match_binding(
*id,
@ -448,6 +474,23 @@ impl MirLowerCtx<'_> {
cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
}
&Pat::Expr(expr) => {
stdx::always!(
mode == MatchingMode::Assign,
"Pat::Expr can only come in destructuring assignments"
);
let Some((lhs_place, current)) = self.lower_expr_as_place(current, expr, false)?
else {
return Ok((current, current_else));
};
self.push_assignment(
current,
lhs_place,
Operand::Copy(cond_place).into(),
expr.into(),
);
(current, current_else)
}
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@ -464,6 +507,18 @@ impl MirLowerCtx<'_> {
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?;
self.push_storage_live(id, current)?;
self.push_match_assignment(current, target_place, mode, cond_place, span);
Ok((current, current_else))
}
fn push_match_assignment(
&mut self,
current: BasicBlockId,
target_place: LocalId,
mode: BindingMode,
cond_place: Place,
span: MirSpan,
) {
self.push_assignment(
current,
target_place.into(),
@ -476,7 +531,6 @@ impl MirLowerCtx<'_> {
},
span,
);
Ok((current, current_else))
}
fn pattern_match_const(

View file

@ -258,6 +258,10 @@ impl Filler<'_> {
| Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_)
| Rvalue::CopyForDeref(_) => (),
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::Deinit(_)
| StatementKind::FakeRead(_)

View file

@ -459,6 +459,10 @@ impl<'a> MirPrettyCtx<'a> {
self.place(p);
w!(self, ")");
}
Rvalue::ThreadLocalRef(n)
| Rvalue::AddressOf(n)
| Rvalue::BinaryOp(n)
| Rvalue::NullaryOp(n) => match *n {},
}
}

View file

@ -3418,11 +3418,11 @@ struct TS(usize);
fn main() {
let x;
[x,] = &[1,];
//^^^^expected &'? [i32; 1], got [{unknown}; _]
//^^^^expected &'? [i32; 1], got [{unknown}]
let x;
[(x,),] = &[(1,),];
//^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
//^^^^^^^expected &'? [(i32,); 1], got [{unknown}]
let x;
((x,),) = &((1,),);
@ -3720,3 +3720,85 @@ fn test() -> bool {
"#]],
);
}
#[test]
fn macro_semitransparent_hygiene() {
check_types(
r#"
macro_rules! m {
() => { let bar: i32; };
}
fn foo() {
let bar: bool;
m!();
bar;
// ^^^ bool
}
"#,
);
}
#[test]
fn macro_expansion_can_refer_variables_defined_before_macro_definition() {
check_types(
r#"
fn foo() {
let v: i32 = 0;
macro_rules! m {
() => { v };
}
let v: bool = true;
m!();
// ^^^^ i32
}
"#,
);
}
#[test]
fn macro_rules_shadowing_works_with_hygiene() {
check_types(
r#"
fn foo() {
let v: bool;
macro_rules! m { () => { v } }
m!();
// ^^^^ bool
let v: char;
macro_rules! m { () => { v } }
m!();
// ^^^^ char
{
let v: u8;
macro_rules! m { () => { v } }
m!();
// ^^^^ u8
let v: i8;
macro_rules! m { () => { v } }
m!();
// ^^^^ i8
let v: i16;
macro_rules! m { () => { v } }
m!();
// ^^^^ i16
{
let v: u32;
macro_rules! m { () => { v } }
m!();
// ^^^^ u32
let v: u64;
macro_rules! m { () => { v } }
m!();
// ^^^^ u64
}
}
}
"#,
);
}

View file

@ -123,7 +123,7 @@ pub(super) struct ClauseElaborator<'a> {
seen: FxHashSet<WhereClause>,
}
impl<'a> ClauseElaborator<'a> {
impl ClauseElaborator<'_> {
fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) {
self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone())))
}
@ -163,10 +163,12 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
let is_trait = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
TypeRef::Path(p) => p.is_self_type(),
_ => false,
},
WherePredicateTypeTarget::TypeRef(type_ref) => {
match &generic_params.types_map[*type_ref] {
TypeRef::Path(p) => p.is_self_type(),
_ => false,
}
}
WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
Some(*local_id) == trait_self
}
@ -257,10 +259,12 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
return true;
}
match func.lookup(db.upcast()).container {
let loc = func.lookup(db.upcast());
match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => {
// Function in an `extern` block are always unsafe to call, except when it has
// `"rust-intrinsic"` ABI there are a few exceptions.
// Function in an `extern` block are always unsafe to call, except when
// it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a
// few exceptions.
let id = block.lookup(db.upcast()).id;
let is_intrinsic =
@ -270,8 +274,8 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
!data.attrs.by_key(&sym::rustc_safe_intrinsic).exists()
} else {
// Extern items are always unsafe
true
// Extern items without `safe` modifier are always unsafe
!data.is_safe()
}
}
_ => false,

View file

@ -4,35 +4,43 @@
//!
//! But we need this for at least LRU caching at the query level.
pub use hir_def::db::{
AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BodyQuery, BodyWithSourceMapQuery,
ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, CrateLangItemsQuery,
CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage,
EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery,
FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery,
ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase,
InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery,
InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query,
InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery,
InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery,
StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery,
TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
GenericParamsWithSourceMapQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery,
IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataWithDiagnosticsQuery,
TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
};
pub use hir_expand::db::{
AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery,
ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
RealSpanMapQuery,
};
pub use hir_ty::db::{
AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
ConstParamTyQuery, FieldTypesQuery, FnDefDatumQuery, FnDefVarianceQuery, GenericDefaultsQuery,
GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage,
ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery,
ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, MirBodyQuery, ProgramClausesForChalkEnvQuery,
ReturnTypeImplTraitsQuery, TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery,
TraitImplsInBlockQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TyQuery, ValueTyQuery,
InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
TypeAliasImplTraitsQuery, ValueTyQuery,
};

View file

@ -165,6 +165,7 @@ pub struct MacroError {
pub precise_location: Option<TextRange>,
pub message: String,
pub error: bool,
pub kind: &'static str,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@ -246,7 +247,7 @@ pub struct UnresolvedAssocItem {
#[derive(Debug)]
pub struct UnresolvedIdent {
pub expr: InFile<AstPtr<ast::Expr>>,
pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
}
#[derive(Debug)]
@ -257,7 +258,7 @@ pub struct PrivateField {
#[derive(Debug)]
pub struct MissingUnsafe {
pub expr: InFile<AstPtr<ast::Expr>>,
pub expr: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
/// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error.
pub only_lint: bool,
}
@ -398,56 +399,46 @@ impl AnyDiagnostic {
.map(|idx| variant_data.fields()[idx].name.clone())
.collect();
match record {
Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
Ok(source_ptr) => {
let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::RecordExpr(record_expr) =
source_ptr.value.to_node(&root)
{
if record_expr.record_expr_field_list().is_some() {
let field_list_parent_path =
record_expr.path().map(|path| AstPtr::new(&path));
return Some(
MissingFields {
file: source_ptr.file_id,
field_list_parent: AstPtr::new(&Either::Left(
record_expr,
)),
field_list_parent_path,
missed_fields,
}
.into(),
);
let record = match record {
Either::Left(record_expr) => {
source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left)
}
Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
};
let file = record.file_id;
let root = record.file_syntax(db.upcast());
match record.value.to_node(&root) {
Either::Left(ast::Expr::RecordExpr(record_expr)) => {
if record_expr.record_expr_field_list().is_some() {
let field_list_parent_path =
record_expr.path().map(|path| AstPtr::new(&path));
return Some(
MissingFields {
file,
field_list_parent: AstPtr::new(&Either::Left(record_expr)),
field_list_parent_path,
missed_fields,
}
}
.into(),
);
}
Err(SyntheticSyntax) => (),
},
Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
Ok(source_ptr) => {
if let Some(ptr) = source_ptr.value.cast::<ast::RecordPat>() {
let root = source_ptr.file_syntax(db.upcast());
let record_pat = ptr.to_node(&root);
if record_pat.record_pat_field_list().is_some() {
let field_list_parent_path =
record_pat.path().map(|path| AstPtr::new(&path));
return Some(
MissingFields {
file: source_ptr.file_id,
field_list_parent: AstPtr::new(&Either::Right(
record_pat,
)),
field_list_parent_path,
missed_fields,
}
.into(),
);
}
Either::Right(ast::Pat::RecordPat(record_pat)) => {
if record_pat.record_pat_field_list().is_some() {
let field_list_parent_path =
record_pat.path().map(|path| AstPtr::new(&path));
return Some(
MissingFields {
file,
field_list_parent: AstPtr::new(&Either::Right(record_pat)),
field_list_parent_path,
missed_fields,
}
}
.into(),
);
}
Err(SyntheticSyntax) => (),
},
}
_ => {}
}
}
BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
@ -541,15 +532,17 @@ impl AnyDiagnostic {
let pat_syntax = |pat| {
source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
};
let expr_or_pat_syntax = |id| match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
ExprOrPatId::PatId(pat) => pat_syntax(pat),
};
Some(match d {
&InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
let expr_or_pat = match expr {
ExprOrPatId::ExprId(expr) => {
source_map.field_syntax(expr).map(AstPtr::wrap_left)
}
ExprOrPatId::PatId(pat) => {
source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
}
ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
};
NoSuchField { field: expr_or_pat, private, variant }.into()
}
@ -562,10 +555,7 @@ impl AnyDiagnostic {
PrivateField { expr, field }.into()
}
&InferenceDiagnostic::PrivateAssocItem { id, item } => {
let expr_or_pat = match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
};
let expr_or_pat = expr_or_pat_syntax(id)?;
let item = item.into();
PrivateAssocItem { expr_or_pat, item }.into()
}
@ -609,15 +599,12 @@ impl AnyDiagnostic {
.into()
}
&InferenceDiagnostic::UnresolvedAssocItem { id } => {
let expr_or_pat = match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
};
let expr_or_pat = expr_or_pat_syntax(id)?;
UnresolvedAssocItem { expr_or_pat }.into()
}
&InferenceDiagnostic::UnresolvedIdent { expr } => {
let expr = expr_syntax(expr)?;
UnresolvedIdent { expr }.into()
&InferenceDiagnostic::UnresolvedIdent { id } => {
let expr_or_pat = expr_or_pat_syntax(id)?;
UnresolvedIdent { expr_or_pat }.into()
}
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
let expr = expr_syntax(expr)?;

View file

@ -12,12 +12,11 @@ use hir_def::{
};
use hir_ty::{
display::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
HirFormatter, SizedByDefault,
hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
},
AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
};
use intern::Interned;
use itertools::Itertools;
use crate::{
@ -113,7 +112,7 @@ impl HirDisplay for Function {
f.write_str(&pat_str)?;
f.write_str(": ")?;
type_ref.hir_fmt(f)?;
type_ref.hir_fmt(f, &data.types_map)?;
}
if data.is_varargs() {
@ -129,28 +128,30 @@ impl HirDisplay for Function {
// Use ugly pattern match to strip the Future trait.
// Better way?
let ret_type = if !data.is_async() {
&data.ret_type
Some(data.ret_type)
} else {
match &*data.ret_type {
TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
TypeBound::Path(path, _) => {
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
match &data.types_map[data.ret_type] {
TypeRef::ImplTrait(bounds) => match &bounds[0] {
TypeBound::Path(path, _) => Some(
*path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
[0]
.type_ref
.as_ref()
.unwrap()
}
_ => &TypeRef::Error,
.unwrap(),
),
_ => None,
},
_ => &TypeRef::Error,
_ => None,
}
};
match ret_type {
TypeRef::Tuple(tup) if tup.is_empty() => {}
ty => {
f.write_str(" -> ")?;
ty.hir_fmt(f)?;
if let Some(ret_type) = ret_type {
match &data.types_map[ret_type] {
TypeRef::Tuple(tup) if tup.is_empty() => {}
_ => {
f.write_str(" -> ")?;
ret_type.hir_fmt(f, &data.types_map)?;
}
}
}
@ -192,23 +193,23 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
impl HirDisplay for SelfParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let data = f.db.function_data(self.func);
let param = data.params.first().unwrap();
match &**param {
let param = *data.params.first().unwrap();
match &data.types_map[param] {
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
{
f.write_char('&')?;
if let Some(lifetime) = lifetime {
if let Some(lifetime) = &ref_.lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
}
if let hir_def::type_ref::Mutability::Mut = mut_ {
if let hir_def::type_ref::Mutability::Mut = ref_.mutability {
f.write_str("mut ")?;
}
f.write_str("self")
}
ty => {
_ => {
f.write_str("self: ")?;
ty.hir_fmt(f)
param.hir_fmt(f, &data.types_map)
}
}
}
@ -393,7 +394,7 @@ impl HirDisplay for Variant {
let data = self.variant_data(f.db);
match &*data {
VariantData::Unit => {}
VariantData::Tuple(fields) => {
VariantData::Tuple { fields, types_map } => {
f.write_char('(')?;
let mut first = true;
for (_, field) in fields.iter() {
@ -403,11 +404,11 @@ impl HirDisplay for Variant {
f.write_str(", ")?;
}
// Enum variant fields must be pub.
field.type_ref.hir_fmt(f)?;
field.type_ref.hir_fmt(f, types_map)?;
}
f.write_char(')')?;
}
VariantData::Record(_) => {
VariantData::Record { .. } => {
if let Some(limit) = f.entity_limit {
write_fields(&self.fields(f.db), false, limit, true, f)?;
}
@ -579,13 +580,13 @@ fn write_generic_params(
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
if let Some(default) = &ty.default {
f.write_str(" = ")?;
default.hir_fmt(f)?;
default.hir_fmt(f, &params.types_map)?;
}
}
TypeOrConstParamData::ConstParamData(c) => {
delim(f)?;
write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
c.ty.hir_fmt(f)?;
c.ty.hir_fmt(f, &params.types_map)?;
if let Some(default) = &c.default {
f.write_str(" = ")?;
@ -615,7 +616,7 @@ fn write_where_clause(
Ok(true)
}
fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
fn has_disaplayable_predicates(params: &GenericParams) -> bool {
params.where_predicates().any(|pred| {
!matches!(
pred,
@ -626,21 +627,20 @@ fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
}
fn write_where_predicates(
params: &Interned<GenericParams>,
params: &GenericParams,
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
use WherePredicate::*;
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
let is_unnamed_type_target =
|params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
matches!(target,
WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
)
};
let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| {
matches!(target,
WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
)
};
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, &params.types_map),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
None => f.write_str("{unnamed}"),
@ -668,7 +668,7 @@ fn write_where_predicates(
TypeBound { target, bound } => {
write_target(target, f)?;
f.write_str(": ")?;
bound.hir_fmt(f)?;
bound.hir_fmt(f, &params.types_map)?;
}
Lifetime { target, bound } => {
let target = target.name.display(f.db.upcast(), f.edition());
@ -681,14 +681,16 @@ fn write_where_predicates(
write!(f, "for<{lifetimes}> ")?;
write_target(target, f)?;
f.write_str(": ")?;
bound.hir_fmt(f)?;
bound.hir_fmt(f, &params.types_map)?;
}
}
while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
f.write_str(" + ")?;
match nxt {
TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
TypeBound { bound, .. } | ForLifetime { bound, .. } => {
bound.hir_fmt(f, &params.types_map)?
}
Lifetime { bound, .. } => {
write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
}
@ -716,7 +718,7 @@ impl HirDisplay for Const {
Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
None => f.write_str("_: ")?,
}
data.type_ref.hir_fmt(f)?;
data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(())
}
}
@ -730,7 +732,7 @@ impl HirDisplay for Static {
f.write_str("mut ")?;
}
write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
data.type_ref.hir_fmt(f)?;
data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(())
}
}
@ -813,11 +815,14 @@ impl HirDisplay for TypeAlias {
write_generic_params(def_id, f)?;
if !data.bounds.is_empty() {
f.write_str(": ")?;
f.write_joined(data.bounds.iter(), " + ")?;
f.write_joined(
data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
" + ",
)?;
}
if let Some(ty) = &data.type_ref {
if let Some(ty) = data.type_ref {
f.write_str(" = ")?;
ty.hir_fmt(f)?;
ty.hir_fmt(f, &data.types_map)?;
}
write_where_clause(def_id, f)?;
Ok(())

View file

@ -58,7 +58,8 @@ use hir_def::{
TypeOrConstParamId, TypeParamId, UnionId,
};
use hir_expand::{
attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError,
ValueResult,
};
use hir_ty::{
all_super_traits, autoderef, check_orphan_rules,
@ -838,7 +839,7 @@ fn macro_call_diagnostics(
let file_id = loc.kind.file_id();
let node =
InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
let (message, error) = err.render_to_string(db.upcast());
let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
let precise_location = if err.span().anchor.file_id == file_id {
Some(
err.span().range
@ -850,7 +851,7 @@ fn macro_call_diagnostics(
} else {
None
};
acc.push(MacroError { node, precise_location, message, error }.into());
acc.push(MacroError { node, precise_location, message, error, kind }.into());
}
if !parse_errors.is_empty() {
@ -916,13 +917,14 @@ fn emit_def_diagnostic_(
DefDiagnosticKind::MacroError { ast, path, err } => {
let item = ast.to_ptr(db.upcast());
let (message, error) = err.render_to_string(db.upcast());
let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
acc.push(
MacroError {
node: InFile::new(ast.file_id, item.syntax_node_ptr()),
precise_location: None,
message: format!("{}: {message}", path.display(db.upcast(), edition)),
error,
kind,
}
.into(),
)
@ -1811,7 +1813,8 @@ impl DefWithBody {
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
}
BodyDiagnostic::MacroError { node, err } => {
let (message, error) = err.render_to_string(db.upcast());
let RenderedExpandError { message, error, kind } =
err.render_to_string(db.upcast());
let precise_location = if err.span().anchor.file_id == node.file_id {
Some(
@ -1829,6 +1832,7 @@ impl DefWithBody {
precise_location,
message,
error,
kind,
}
.into()
}
@ -1885,7 +1889,7 @@ impl DefWithBody {
let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into());
for expr in unafe_exprs {
match source_map.expr_syntax(expr) {
match source_map.expr_or_pat_syntax(expr) {
Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()),
Err(SyntheticSyntax) => {
// FIXME: Here and elsewhere in this file, the `expr` was
@ -2420,8 +2424,8 @@ impl SelfParam {
func_data
.params
.first()
.map(|param| match &**param {
TypeRef::Reference(.., mutability) => match mutability {
.map(|&param| match &func_data.types_map[param] {
TypeRef::Reference(ref_) => match ref_.mutability {
hir_def::type_ref::Mutability::Shared => Access::Shared,
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
},
@ -2747,10 +2751,6 @@ impl TypeAlias {
Module { id: self.id.module(db.upcast()) }
}
pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
db.type_alias_data(self.id).type_ref.as_deref().cloned()
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::from_def(db, self.id)
}
@ -3481,7 +3481,7 @@ impl Local {
LocalSource {
local: self,
source: src.map(|ast| match ast.to_node(&root) {
ast::Pat::IdentPat(it) => Either::Left(it),
Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
_ => unreachable!("local with non ident-pattern"),
}),
}
@ -3510,7 +3510,7 @@ impl Local {
LocalSource {
local: self,
source: src.map(|ast| match ast.to_node(&root) {
ast::Pat::IdentPat(it) => Either::Left(it),
Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
_ => unreachable!("local with non ident-pattern"),
}),
}
@ -4235,10 +4235,7 @@ impl CaptureUsages {
}
mir::MirSpan::PatId(pat) => {
if let Ok(pat) = source_map.pat_syntax(pat) {
result.push(CaptureUsageSource {
is_ref,
source: pat.map(AstPtr::wrap_right),
});
result.push(CaptureUsageSource { is_ref, source: pat });
}
}
mir::MirSpan::BindingId(binding) => result.extend(
@ -4246,10 +4243,7 @@ impl CaptureUsages {
.patterns_for_binding(binding)
.iter()
.filter_map(|&pat| source_map.pat_syntax(pat).ok())
.map(|pat| CaptureUsageSource {
is_ref,
source: pat.map(AstPtr::wrap_right),
}),
.map(|pat| CaptureUsageSource { is_ref, source: pat }),
),
mir::MirSpan::SelfParam | mir::MirSpan::Unknown => {
unreachable!("invalid capture usage span")

View file

@ -11,13 +11,13 @@ use std::{
use either::Either;
use hir_def::{
hir::Expr,
hir::{Expr, ExprOrPatId},
lower::LowerCtx,
nameres::{MacroSubNs, ModuleOrigin},
path::ModPath,
resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability,
AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
type_ref::{Mutability, TypesMap, TypesSourceMap},
AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
};
use hir_expand::{
attrs::collect_attrs,
@ -45,7 +45,7 @@ use syntax::{
use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name,
@ -154,7 +154,7 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
}
}
impl<'db, DB: HirDatabase> Semantics<'db, DB> {
impl<DB: HirDatabase> Semantics<'_, DB> {
pub fn new(db: &DB) -> Semantics<'_, DB> {
let impl_ = SemanticsImpl::new(db);
Semantics { db, imp: impl_ }
@ -203,6 +203,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
}
pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
self.imp.resolve_range_pat(range_pat).map(Struct::from)
}
pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
self.imp.resolve_range_expr(range_expr).map(Struct::from)
}
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
self.imp.resolve_await_to_poll(await_expr).map(Function::from)
}
@ -892,29 +900,8 @@ impl<'db> SemanticsImpl<'db> {
f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContextId) -> ControlFlow<T>,
) -> Option<T> {
let _p = tracing::info_span!("descend_into_macros_impl").entered();
let (sa, span, file_id) = token
.parent()
.and_then(|parent| {
self.analyze_impl(InRealFile::new(file_id, &parent).into(), None, false)
})
.and_then(|sa| {
let file_id = sa.file_id.file_id()?;
Some((
sa,
self.db.real_span_map(file_id).span_for_range(token.text_range()),
HirFileId::from(file_id),
))
})?;
let mut m_cache = self.macro_call_cache.borrow_mut();
let def_map = sa.resolver.def_map();
// A stack of tokens to process, along with the file they came from
// These are tracked to know which macro calls we still have to look into
// the tokens themselves aren't that interesting as the span that is being used to map
// things down never changes.
let mut stack: Vec<(_, SmallVec<[_; 2]>)> =
vec![(file_id, smallvec![(token, SyntaxContextId::ROOT)])];
let span = self.db.real_span_map(file_id).span_for_range(token.text_range());
// Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
@ -926,7 +913,6 @@ impl<'db> SemanticsImpl<'db> {
.map(SmallVec::<[_; 2]>::from_iter),
)
})?;
// we have found a mapping for the token if the vec is non-empty
let res = mapped_tokens.is_empty().not().then_some(());
// requeue the tokens we got from mapping our current token down
@ -934,6 +920,24 @@ impl<'db> SemanticsImpl<'db> {
res
};
// A stack of tokens to process, along with the file they came from
// These are tracked to know which macro calls we still have to look into
// the tokens themselves aren't that interesting as the span that is being used to map
// things down never changes.
let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id);
match include {
Some(include) => {
// include! inputs are always from real files, so they only need to be handled once upfront
process_expansion_for_token(&mut stack, include)?;
}
None => {
stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)]));
}
}
let mut m_cache = self.macro_call_cache.borrow_mut();
// Filters out all tokens that contain the given range (usually the macro call), any such
// token is redundant as the corresponding macro call has already been processed
let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
@ -941,6 +945,10 @@ impl<'db> SemanticsImpl<'db> {
};
while let Some((expansion, ref mut tokens)) = stack.pop() {
// Reverse the tokens so we prefer first tokens (to accommodate for popping from the
// back)
// alternatively we could pop from the front but that would shift the content on every pop
tokens.reverse();
while let Some((token, ctx)) = tokens.pop() {
let was_not_remapped = (|| {
// First expand into attribute invocations
@ -1011,7 +1019,16 @@ impl<'db> SemanticsImpl<'db> {
) {
call.as_macro_file()
} else {
sa.expand(self.db, mcall.as_ref())?
token
.parent()
.and_then(|parent| {
self.analyze_impl(
InFile::new(expansion, &parent),
None,
false,
)
})?
.expand(self.db, mcall.as_ref())?
};
m_cache.insert(mcall, it);
it
@ -1081,9 +1098,16 @@ impl<'db> SemanticsImpl<'db> {
attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
// Not an attribute, nor a derive, so it's either an intert attribute or a derive helper
// Try to resolve to a derive helper and downmap
let resolver = &token
.parent()
.and_then(|parent| {
self.analyze_impl(InFile::new(expansion, &parent), None, false)
})?
.resolver;
let id = self.db.ast_id_map(expansion).ast_id(&adt);
let helpers =
def_map.derive_helpers_in_scope(InFile::new(expansion, id))?;
let helpers = resolver
.def_map()
.derive_helpers_in_scope(InFile::new(expansion, id))?;
if !helpers.is_empty() {
let text_range = attr.syntax().text_range();
@ -1245,19 +1269,28 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
let analyze = self.analyze(ty.syntax())?;
let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
self.db,
&analyze.resolver,
&types_map,
None,
analyze.resolver.type_owner(),
)
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
.lower_ty(type_ref);
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
}
pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
let analyze = self.analyze(path.syntax())?;
let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?;
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
TypeNs::TraitId(id) => Some(Trait { id }),
@ -1357,6 +1390,14 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
}
fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
}
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
}
@ -1755,7 +1796,9 @@ impl<'db> SemanticsImpl<'db> {
}
if let Some(parent) = ast::Expr::cast(parent.clone()) {
if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
if let Some(ExprOrPatId::ExprId(expr_id)) =
source_map.node_expr(InFile { file_id, value: &parent })
{
if let Expr::Unsafe { .. } = body[expr_id] {
break true;
}
@ -1928,10 +1971,19 @@ impl SemanticsScope<'_> {
/// Resolve a path as-if it was written at the given scope. This is
/// necessary a heuristic, as it doesn't take hygiene into account.
pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
let ctx = LowerCtx::new(self.db.upcast(), self.file_id);
let path = Path::from_src(&ctx, path.clone())?;
resolve_hir_path(self.db, &self.resolver, &path)
pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
let path = Path::from_src(&ctx, ast_path.clone())?;
resolve_hir_path(
self.db,
&self.resolver,
&path,
name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())),
&types_map,
)
}
/// Iterates over associated types that may be specified after the given path (using

View file

@ -104,7 +104,7 @@ use hir_expand::{
};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use span::{FileId, MacroFileId};
use span::{EditionedFileId, FileId, MacroFileId};
use stdx::impl_from;
use syntax::{
ast::{self, HasName},
@ -118,9 +118,27 @@ pub(super) struct SourceToDefCache {
pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>,
expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>,
pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>,
pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>,
}
impl SourceToDefCache {
pub(super) fn get_or_insert_include_for(
&mut self,
db: &dyn HirDatabase,
file: EditionedFileId,
) -> Option<MacroFileId> {
if let Some(&m) = self.included_file_cache.get(&file) {
return m;
}
self.included_file_cache.insert(file, None);
for &crate_id in db.relevant_crates(file.into()).iter() {
db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| {
self.included_file_cache.insert(file_id, Some(MacroFileId { macro_call_id }));
});
}
self.included_file_cache.get(&file).copied().flatten()
}
pub(super) fn get_or_insert_expansion(
&mut self,
sema: &SemanticsImpl<'_>,
@ -163,9 +181,13 @@ impl SourceToDefCtx<'_, '_> {
.include_macro_invoc(crate_id)
.iter()
.filter(|&&(_, file_id)| file_id == file)
.flat_map(|(call, _)| {
.flat_map(|&(macro_call_id, file_id)| {
self.cache
.included_file_cache
.insert(file_id, Some(MacroFileId { macro_call_id }));
modules(
call.lookup(self.db.upcast())
macro_call_id
.lookup(self.db.upcast())
.kind
.file_id()
.original_file(self.db.upcast())
@ -306,7 +328,7 @@ impl SourceToDefCtx<'_, '_> {
.position(|it| it == *src.value)?;
let container = self.find_pat_or_label_container(src.syntax_ref())?;
let (_, source_map) = self.db.body_with_source_map(container);
let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?;
let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?;
Some(InlineAsmOperand { owner: container, expr, index })
}
@ -350,7 +372,8 @@ impl SourceToDefCtx<'_, '_> {
let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?;
let container = self.find_pat_or_label_container(src.syntax_ref())?;
let (body, source_map) = self.db.body_with_source_map(container);
let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?;
let break_or_continue =
source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?;
let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else {
return None;
};

View file

@ -7,21 +7,26 @@
//! purely for "IDE needs".
use std::iter::{self, once};
use crate::{
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
};
use either::Either;
use hir_def::{
body::{
scope::{ExprScopes, ScopeId},
Body, BodySourceMap,
Body, BodySourceMap, HygieneId,
},
hir::{BindingId, ExprId, Pat, PatId},
hir::{BindingId, ExprId, ExprOrPatId, Pat, PatId},
lang_item::LangItem,
lower::LowerCtx,
nameres::MacroSubNs,
path::{ModPath, Path, PathKind},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
type_ref::Mutability,
type_ref::{Mutability, TypesMap, TypesSourceMap},
AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
};
use hir_expand::{
mod_path::path,
@ -40,18 +45,13 @@ use hir_ty::{
use intern::sym;
use itertools::Itertools;
use smallvec::SmallVec;
use syntax::ast::{RangeItem, RangeOp};
use syntax::{
ast::{self, AstNode},
SyntaxKind, SyntaxNode, TextRange, TextSize,
};
use triomphe::Arc;
use crate::{
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
};
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
/// original source files. It should not be used inside the HIR itself.
#[derive(Debug)]
@ -120,7 +120,7 @@ impl SourceAnalyzer {
self.def.as_ref().map(|(_, body, _)| &**body)
}
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprOrPatId> {
let src = match expr {
ast::Expr::MacroExpr(expr) => {
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
@ -174,7 +174,9 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
expr: &ast::Expr,
) -> Option<&[Adjustment]> {
let expr_id = self.expr_id(db, expr)?;
// It is safe to omit destructuring assignments here because they have no adjustments (neither
// expressions nor patterns).
let expr_id = self.expr_id(db, expr)?.as_expr()?;
let infer = self.infer.as_ref()?;
infer.expr_adjustments.get(&expr_id).map(|v| &**v)
}
@ -186,9 +188,9 @@ impl SourceAnalyzer {
) -> Option<(Type, Option<Type>)> {
let expr_id = self.expr_id(db, expr)?;
let infer = self.infer.as_ref()?;
let coerced = infer
.expr_adjustments
.get(&expr_id)
let coerced = expr_id
.as_expr()
.and_then(|expr_id| infer.expr_adjustments.get(&expr_id))
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
let ty = infer[expr_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
@ -268,7 +270,7 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Callable> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
let ty = Type::new_with_resolver(db, &self.resolver, ty);
@ -282,7 +284,7 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Function> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
@ -293,7 +295,7 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Either<Function, Field>> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let inference_result = self.infer.as_ref()?;
match inference_result.method_resolution(expr_id) {
Some((f_in_trait, substs)) => Some(Either::Left(
@ -322,7 +324,7 @@ impl SourceAnalyzer {
field: &ast::FieldExpr,
) -> Option<Either<Field, TupleField>> {
let &(def, ..) = self.def.as_ref()?;
let expr_id = self.expr_id(db, &field.clone().into())?;
let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
self.infer.as_ref()?.field_resolution(expr_id).map(|it| {
it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
})
@ -334,7 +336,7 @@ impl SourceAnalyzer {
field: &ast::FieldExpr,
) -> Option<Either<Either<Field, TupleField>, Function>> {
let &(def, ..) = self.def.as_ref()?;
let expr_id = self.expr_id(db, &field.clone().into())?;
let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
let inference_result = self.infer.as_ref()?;
match inference_result.field_resolution(expr_id) {
Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField {
@ -348,6 +350,45 @@ impl SourceAnalyzer {
}
}
pub(crate) fn resolve_range_pat(
&self,
db: &dyn HirDatabase,
range_pat: &ast::RangePat,
) -> Option<StructId> {
let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
(RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
(RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
(RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
(RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
(RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
(RangeOp::Exclusive, None, None) => return None,
(RangeOp::Inclusive, None, None) => return None,
(RangeOp::Inclusive, Some(_), None) => return None,
};
self.resolver.resolve_known_struct(db.upcast(), &path)
}
pub(crate) fn resolve_range_expr(
&self,
db: &dyn HirDatabase,
range_expr: &ast::RangeExpr,
) -> Option<StructId> {
let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
(RangeOp::Exclusive, None, None) => path![core::ops::RangeFull],
(RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
(RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
(RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
(RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
(RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
// [E0586] inclusive ranges must be bounded at the end
(RangeOp::Inclusive, None, None) => return None,
(RangeOp::Inclusive, Some(_), None) => return None,
};
self.resolver.resolve_known_struct(db.upcast(), &path)
}
pub(crate) fn resolve_await_to_poll(
&self,
db: &dyn HirDatabase,
@ -403,7 +444,7 @@ impl SourceAnalyzer {
self.infer
.as_ref()
.and_then(|infer| {
let expr = self.expr_id(db, &prefix_expr.clone().into())?;
let expr = self.expr_id(db, &prefix_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
db,
@ -449,7 +490,7 @@ impl SourceAnalyzer {
.infer
.as_ref()
.and_then(|infer| {
let expr = self.expr_id(db, &index_expr.clone().into())?;
let expr = self.expr_id(db, &index_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
db,
@ -521,7 +562,8 @@ impl SourceAnalyzer {
let expr = ast::Expr::from(record_expr);
let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
let local_name = field.field_name()?.as_name();
let ast_name = field.field_name()?;
let local_name = ast_name.as_name();
let local = if field.name_ref().is_some() {
None
} else {
@ -530,15 +572,19 @@ impl SourceAnalyzer {
PathKind::Plain,
once(local_name.clone()),
));
match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
match self.resolver.resolve_path_in_value_ns_fully(
db.upcast(),
&path,
name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),
) {
Some(ValueNs::LocalBinding(binding_id)) => {
Some(Local { binding_id, parent: self.resolver.body_owner()? })
}
_ => None,
}
};
let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
let (_, subst) = self.infer.as_ref()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
let variant = self.infer.as_ref()?.variant_resolution_for_expr_or_pat(expr_id)?;
let variant_data = variant.variant_data(db.upcast());
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
let field_ty =
@ -568,7 +614,10 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>,
) -> Option<Macro> {
let ctx = LowerCtx::new(db.upcast(), macro_call.file_id);
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
self.resolver
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
@ -586,7 +635,7 @@ impl SourceAnalyzer {
Pat::Path(path) => path,
_ => return None,
};
let res = resolve_hir_path(db, &self.resolver, path)?;
let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
match res {
PathResolution::Def(def) => Some(def),
_ => None,
@ -606,10 +655,10 @@ impl SourceAnalyzer {
let infer = self.infer.as_deref()?;
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
let expr_id = self.expr_id(db, &path_expr.into())?;
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {
let assoc = match assoc {
AssocItemId::FunctionId(f_in_trait) => {
match infer.type_of_expr.get(expr_id) {
match infer.type_of_expr_or_pat(expr_id) {
None => assoc,
Some(func_ty) => {
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
@ -634,7 +683,7 @@ impl SourceAnalyzer {
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
infer.variant_resolution_for_expr(expr_id)
infer.variant_resolution_for_expr_or_pat(expr_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
@ -658,7 +707,7 @@ impl SourceAnalyzer {
} else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
let expr_id = self.expr_id(db, &rec_lit.into())?;
if let Some(VariantId::EnumVariantId(variant)) =
infer.variant_resolution_for_expr(expr_id)
infer.variant_resolution_for_expr_or_pat(expr_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
@ -680,14 +729,16 @@ impl SourceAnalyzer {
return resolved;
}
let ctx = LowerCtx::new(db.upcast(), self.file_id);
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?;
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
// trying to resolve foo::bar.
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
if use_tree.coloncolon_token().is_some() {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map);
}
}
@ -704,7 +755,7 @@ impl SourceAnalyzer {
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
// trying to resolve foo::bar.
if path.parent_path().is_some() {
return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
None if meta_path.is_some() => {
path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
@ -775,9 +826,16 @@ impl SourceAnalyzer {
};
}
if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map)
} else {
resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
resolve_hir_path_(
db,
&self.resolver,
&hir_path,
prefer_value_ns,
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
&types_map,
)
}
}
@ -790,10 +848,16 @@ impl SourceAnalyzer {
let infer = self.infer.as_ref()?;
let expr_id = self.expr_id(db, &literal.clone().into())?;
let substs = infer.type_of_expr[expr_id].as_adt()?.1;
let substs = infer[expr_id].as_adt()?.1;
let (variant, missing_fields, _exhaustive) =
record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
let (variant, missing_fields, _exhaustive) = match expr_id {
ExprOrPatId::ExprId(expr_id) => {
record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?
}
ExprOrPatId::PatId(pat_id) => {
record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?
}
};
let res = self.missing_fields(db, substs, variant, missing_fields);
Some(res)
}
@ -856,7 +920,7 @@ impl SourceAnalyzer {
) -> Option<VariantId> {
let infer = self.infer.as_ref()?;
let expr_id = self.expr_id(db, &record_lit.into())?;
infer.variant_resolution_for_expr(expr_id)
infer.variant_resolution_for_expr_or_pat(expr_id)
}
pub(crate) fn is_unsafe_macro_call_expr(
@ -867,14 +931,24 @@ impl SourceAnalyzer {
if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
let mut is_unsafe = false;
unsafe_expressions(
db,
infer,
*def,
body,
expanded_expr,
&mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
);
let mut walk_expr = |expr_id| {
unsafe_expressions(
db,
infer,
*def,
body,
expr_id,
&mut |UnsafeExpr { inside_unsafe_block, .. }| {
is_unsafe |= !inside_unsafe_block
},
)
};
match expanded_expr {
ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
ExprOrPatId::PatId(expanded_pat) => {
body.walk_exprs_in_pat(expanded_pat, &mut walk_expr)
}
}
return is_unsafe;
}
}
@ -887,7 +961,7 @@ impl SourceAnalyzer {
format_args: InFile<&ast::FormatArgsExpr>,
offset: TextSize,
) -> Option<(TextRange, Option<PathResolution>)> {
let implicits = self.body_source_map()?.implicit_format_args(format_args)?;
let (hygiene, implicits) = self.body_source_map()?.implicit_format_args(format_args)?;
implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| {
(
*range,
@ -899,6 +973,7 @@ impl SourceAnalyzer {
PathKind::Plain,
Some(name.clone()),
)),
hygiene,
),
)
})
@ -925,22 +1000,22 @@ impl SourceAnalyzer {
db: &'a dyn HirDatabase,
format_args: InFile<&ast::FormatArgsExpr>,
) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map(
move |(range, name)| {
(
*range,
resolve_hir_value_path(
db,
&self.resolver,
self.resolver.body_owner(),
&Path::from_known_path_with_no_generic(ModPath::from_segments(
PathKind::Plain,
Some(name.clone()),
)),
),
)
},
))
let (hygiene, names) = self.body_source_map()?.implicit_format_args(format_args)?;
Some(names.iter().map(move |(range, name)| {
(
*range,
resolve_hir_value_path(
db,
&self.resolver,
self.resolver.body_owner(),
&Path::from_known_path_with_no_generic(ModPath::from_segments(
PathKind::Plain,
Some(name.clone()),
)),
hygiene,
),
)
}))
}
pub(crate) fn as_asm_parts(
@ -991,7 +1066,7 @@ impl SourceAnalyzer {
}
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
}
}
@ -1004,7 +1079,7 @@ fn scope_for(
node.ancestors_with_macros(db.upcast())
.take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
.filter_map(|it| it.map(ast::Expr::cast).transpose())
.filter_map(|it| source_map.node_expr(it.as_ref()))
.filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
.find_map(|it| scopes.scope_for(it))
}
@ -1086,8 +1161,10 @@ pub(crate) fn resolve_hir_path(
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
hygiene: HygieneId,
types_map: &TypesMap,
) -> Option<PathResolution> {
resolve_hir_path_(db, resolver, path, false)
resolve_hir_path_(db, resolver, path, false, hygiene, types_map)
}
#[inline]
@ -1107,13 +1184,20 @@ fn resolve_hir_path_(
resolver: &Resolver,
path: &Path,
prefer_value_ns: bool,
hygiene: HygieneId,
types_map: &TypesMap,
) -> Option<PathResolution> {
let types = || {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => {
let (_, res) =
TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
.lower_ty_ext(type_ref);
let (_, res) = TyLoweringContext::new_maybe_unowned(
db,
resolver,
types_map,
None,
resolver.type_owner(),
)
.lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}
None => {
@ -1172,7 +1256,7 @@ fn resolve_hir_path_(
};
let body_owner = resolver.body_owner();
let values = || resolve_hir_value_path(db, resolver, body_owner, path);
let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene);
let items = || {
resolver
@ -1197,8 +1281,9 @@ fn resolve_hir_value_path(
resolver: &Resolver,
body_owner: Option<DefWithBodyId>,
path: &Path,
hygiene: HygieneId,
) -> Option<PathResolution> {
resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| {
resolver.resolve_path_in_value_ns_fully(db.upcast(), path, hygiene).and_then(|val| {
let res = match val {
ValueNs::LocalBinding(binding_id) => {
let var = Local { parent: body_owner?, binding_id };
@ -1233,13 +1318,19 @@ fn resolve_hir_path_qualifier(
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
types_map: &TypesMap,
) -> Option<PathResolution> {
(|| {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => {
let (_, res) =
TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
.lower_ty_ext(type_ref);
let (_, res) = TyLoweringContext::new_maybe_unowned(
db,
resolver,
types_map,
None,
resolver.type_owner(),
)
.lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}
None => {
@ -1303,3 +1394,13 @@ fn resolve_hir_path_qualifier(
.map(|it| PathResolution::Def(it.into()))
})
}
pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> HygieneId {
let Some(macro_file) = name.file_id.macro_file() else {
return HygieneId::ROOT;
};
let span_map = db.expansion_span_map(macro_file);
let ctx = span_map.span_at(name.value.text_range().start()).ctx;
let ctx = db.lookup_intern_syntax_context(ctx);
HygieneId::new(ctx.opaque_and_semitransparent)
}

View file

@ -8,7 +8,10 @@ use hir_def::{
TraitId,
};
use hir_expand::HirFileId;
use hir_ty::{db::HirDatabase, display::HirDisplay};
use hir_ty::{
db::HirDatabase,
display::{hir_display_with_types_map, HirDisplay},
};
use span::Edition;
use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
@ -214,8 +217,11 @@ impl<'a> SymbolCollector<'a> {
fn collect_from_impl(&mut self, impl_id: ImplId) {
let impl_data = self.db.impl_data(impl_id);
let impl_name =
Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string()));
let impl_name = Some(
hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
.display(self.db, self.edition)
.to_smolstr(),
);
self.with_container_name(impl_name, |s| {
for &assoc_item_id in impl_data.items.iter() {
s.push_assoc_item(assoc_item_id)

View file

@ -23,7 +23,6 @@ tracing.workspace = true
# local deps
stdx.workspace = true
syntax.workspace = true
text-edit.workspace = true
ide-db.workspace = true
hir.workspace = true

View file

@ -1,5 +1,6 @@
use either::Either;
use hir::ModuleDef;
use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@ -19,7 +20,6 @@ use syntax::{
},
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
};
use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists},
@ -1095,6 +1095,7 @@ fn main() {
#[test]
fn field_enum_cross_file() {
// FIXME: The import is missing
check_assist(
bool_to_enum,
r#"
@ -1132,7 +1133,7 @@ fn foo() {
}
//- /main.rs
use foo::{Bool, Foo};
use foo::Foo;
mod foo;

View file

@ -1,4 +1,5 @@
use hir::{sym, HasVisibility};
use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@ -8,7 +9,6 @@ use ide_db::{
};
use itertools::Itertools;
use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists, SourceChangeBuilder},

View file

@ -1,3 +1,4 @@
use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@ -8,7 +9,6 @@ use syntax::{
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
ted,
};
use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists, SourceChangeBuilder},

View file

@ -41,7 +41,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
acc.add(
AssistId("remove_dbg", AssistKind::Refactor),
AssistId("remove_dbg", AssistKind::QuickFix),
"Remove dbg!()",
replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
|builder| {

View file

@ -1,6 +1,7 @@
use std::collections::hash_map::Entry;
use hir::{FileRange, HirFileIdExt, InFile, InRealFile, Module, ModuleSource};
use ide_db::text_edit::TextRange;
use ide_db::{
defs::Definition,
search::{FileReference, ReferenceCategory, SearchScope},
@ -10,7 +11,6 @@ use syntax::{
ast::{self, Rename},
AstNode,
};
use text_edit::TextRange;
use crate::{AssistContext, AssistId, AssistKind, Assists};

View file

@ -1,4 +1,5 @@
use hir::{FileRange, Semantics};
use ide_db::text_edit::TextRange;
use ide_db::{
defs::Definition,
search::{SearchScope, UsageSearchResult},
@ -11,7 +12,6 @@ use syntax::{
},
match_ast, ted, AstNode,
};
use text_edit::TextRange;
use crate::{AssistContext, AssistId, AssistKind, Assists};

View file

@ -34,6 +34,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) {
return None;
}
let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
let match_arm_body = match_arm.expr()?;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -223,9 +223,9 @@ mod handlers {
mod unnecessary_async;
mod unqualify_method_call;
mod unwrap_block;
mod unwrap_result_return_type;
mod unwrap_return_type;
mod unwrap_tuple;
mod wrap_return_type_in_result;
mod wrap_return_type;
mod wrap_unwrap_cfg_attr;
pub(crate) fn all() -> &'static [Handler] {
@ -301,6 +301,7 @@ mod handlers {
inline_call::inline_into_callers,
inline_const_as_literal::inline_const_as_literal,
inline_local_variable::inline_local_variable,
inline_macro::inline_macro,
inline_type_alias::inline_type_alias,
inline_type_alias::inline_type_alias_uses,
into_to_qualified_from::into_to_qualified_from,
@ -326,6 +327,7 @@ mod handlers {
raw_string::add_hash,
raw_string::make_usual_string,
raw_string::remove_hash,
remove_dbg::remove_dbg,
remove_mut::remove_mut,
remove_unused_imports::remove_unused_imports,
remove_unused_param::remove_unused_param,
@ -355,10 +357,10 @@ mod handlers {
unmerge_use::unmerge_use,
unnecessary_async::unnecessary_async,
unwrap_block::unwrap_block,
unwrap_result_return_type::unwrap_result_return_type,
unwrap_return_type::unwrap_return_type,
unwrap_tuple::unwrap_tuple,
unqualify_method_call::unqualify_method_call,
wrap_return_type_in_result::wrap_return_type_in_result,
wrap_return_type::wrap_return_type,
wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr,
// These are manually sorted for better priorities. By default,
@ -381,9 +383,6 @@ mod handlers {
generate_getter_or_setter::generate_setter,
generate_delegate_methods::generate_delegate_methods,
generate_deref::generate_deref,
//
remove_dbg::remove_dbg,
inline_macro::inline_macro,
// Are you sure you want to add new assist here, and not to the
// sorted list above?
]

View file

@ -3264,6 +3264,20 @@ fn foo() {
)
}
#[test]
fn doctest_unwrap_option_return_type() {
check_doc_test(
"unwrap_option_return_type",
r#####"
//- minicore: option
fn foo() -> Option<i32>$0 { Some(42i32) }
"#####,
r#####"
fn foo() -> i32 { 42i32 }
"#####,
)
}
#[test]
fn doctest_unwrap_result_return_type() {
check_doc_test(
@ -3297,6 +3311,20 @@ fn main() {
)
}
#[test]
fn doctest_wrap_return_type_in_option() {
check_doc_test(
"wrap_return_type_in_option",
r#####"
//- minicore: option
fn foo() -> i32$0 { 42i32 }
"#####,
r#####"
fn foo() -> Option<i32> { Some(42i32) }
"#####,
)
}
#[test]
fn doctest_wrap_return_type_in_result() {
check_doc_test(

View file

@ -25,7 +25,6 @@ base-db.workspace = true
ide-db.workspace = true
stdx.workspace = true
syntax.workspace = true
text-edit.workspace = true
# 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

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