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

Subtree update of `rust-analyzer`

r? `@ghost`
This commit is contained in:
bors 2024-10-29 10:04:37 +00:00
commit e8398b14be
218 changed files with 7252 additions and 3375 deletions

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
@ -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/*

45
Cargo.lock generated
View file

@ -164,6 +164,7 @@ dependencies = [
"rustc-hash 2.0.0",
"syntax",
"syntax-bridge",
"tracing",
"tt",
]
@ -556,6 +557,7 @@ dependencies = [
"syntax-bridge",
"test-fixture",
"test-utils",
"text-size",
"tracing",
"triomphe",
"tt",
@ -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",
]
@ -743,7 +742,6 @@ dependencies = [
"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",
]
@ -1497,9 +1493,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_abi"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac"
checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
dependencies = [
"bitflags 2.6.0",
"ra-ap-rustc_index",
@ -1508,9 +1504,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7"
checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros",
@ -1519,9 +1515,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index_macros"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997"
checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
dependencies = [
"proc-macro2",
"quote",
@ -1530,9 +1526,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_lexer"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1"
checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
dependencies = [
"unicode-properties",
"unicode-xid",
@ -1540,9 +1536,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_parse_format"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635"
checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
@ -1550,9 +1546,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_pattern_analysis"
version = "0.73.0"
version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293"
checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.0.0",
@ -1884,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",
@ -1978,7 +1974,6 @@ dependencies = [
"smol_str",
"stdx",
"test-utils",
"text-edit",
"tracing",
"triomphe",
]
@ -2026,14 +2021,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "text-edit"
version = "0.0.0"
dependencies = [
"itertools",
"text-size",
]
[[package]]
name = "text-size"
version = "1.1.1"

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,17 +79,16 @@ 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.73", default-features = false }
ra-ap-rustc_parse_format = { version = "0.73", default-features = false }
ra-ap-rustc_index = { version = "0.73", default-features = false }
ra-ap-rustc_abi = { version = "0.73", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.73", 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" }
@ -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,
})
@ -182,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 {
@ -216,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(),
})
}
}
@ -343,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 {
@ -368,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;
@ -387,6 +392,7 @@ impl ImplData {
is_negative,
is_unsafe,
macro_calls,
types_map: impl_def.types_map.clone(),
}),
DefDiagnostics::new(diagnostics),
)
@ -532,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 {
@ -556,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(),
})
}
}
@ -567,12 +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 {
@ -583,12 +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! {
@ -762,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>,
}
@ -792,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)]
@ -805,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,
}
@ -814,9 +1008,10 @@ 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)]
@ -827,15 +1022,16 @@ pub struct Static {
pub mutable: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
pub type_ref: Interned<TypeRef>,
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]>,
@ -846,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)]
@ -866,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)]
@ -968,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
};
@ -447,18 +547,27 @@ impl<'a> Ctx<'a> {
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);
}
@ -470,37 +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, has_safe_kw, has_unsafe_kw };
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))
}
@ -539,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)
}
@ -554,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();
@ -584,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>> {
@ -692,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 {
@ -715,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(),
}
}
@ -743,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),
@ -767,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();
@ -777,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());
@ -298,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, "...");
}
@ -307,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, " {{ ... }}");
@ -316,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));
@ -327,6 +343,7 @@ impl Printer<'_> {
*kind,
fields,
generic_params,
types_map,
);
if matches!(kind, FieldsShape::Record) {
wln!(self);
@ -335,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));
@ -345,6 +363,7 @@ impl Printer<'_> {
FieldsShape::Record,
fields,
generic_params,
types_map,
);
wln!(self);
}
@ -358,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 ");
@ -378,7 +399,7 @@ 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) => {
@ -390,6 +411,7 @@ impl Printer<'_> {
ast_id,
has_safe_kw,
has_unsafe_kw,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
@ -404,7 +426,7 @@ impl Printer<'_> {
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);
}
@ -449,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 {
@ -461,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 {
@ -474,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, ";");
@ -543,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) {
@ -586,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);
}
}
}
@ -640,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

@ -191,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 =
@ -210,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

@ -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

@ -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 && !static_data.has_safe_kw) {
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

@ -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
}

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)
}
@ -928,16 +936,7 @@ impl<'db> SemanticsImpl<'db> {
}
}
let (file_id, tokens) = stack.first()?;
// make sure we pick the token in the expanded include if we encountered an include,
// otherwise we'll get the wrong semantics
let sa =
tokens.first()?.0.parent().and_then(|parent| {
self.analyze_impl(InFile::new(*file_id, &parent), None, false)
})?;
let mut m_cache = self.macro_call_cache.borrow_mut();
let def_map = sa.resolver.def_map();
// 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
@ -946,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
@ -1016,8 +1019,16 @@ impl<'db> SemanticsImpl<'db> {
) {
call.as_macro_file()
} else {
// FIXME: This is wrong, the SourceAnalyzer might be invalid here
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
@ -1087,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();
@ -1251,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 }),
@ -1363,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)
}
@ -1761,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;
}
@ -1934,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

@ -328,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 })
}
@ -372,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},

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()?;

View file

@ -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,
@ -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

@ -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

View file

@ -32,6 +32,7 @@
//! ```
use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::HasDocs, path_transform::PathTransform,
syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind,
@ -40,7 +41,6 @@ use syntax::{
ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds},
format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
};
use text_edit::TextEdit;
use crate::{
context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,

View file

@ -7,7 +7,6 @@ use ide_db::{
base_db::{SourceRootDatabase, VfsPath},
FxHashSet, RootDatabase, SymbolKind,
};
use stdx::IsNoneOr;
use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
use crate::{context::CompletionContext, CompletionItem, Completions};
@ -66,7 +65,7 @@ pub(crate) fn complete_mod(
.iter()
.filter(|&submodule_candidate_file| submodule_candidate_file != module_definition_file)
.filter(|&submodule_candidate_file| {
IsNoneOr::is_none_or(module_declaration_file, |it| it != submodule_candidate_file)
module_declaration_file.is_none_or(|it| it != submodule_candidate_file)
})
.filter_map(|submodule_file| {
let submodule_path = source_root.path_for_file(&submodule_file)?;

View file

@ -3,6 +3,7 @@
mod format_like;
use hir::ItemInNs;
use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::{Documentation, HasDocs},
imports::insert_use::ImportScope,
@ -15,7 +16,6 @@ use syntax::{
SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
TextRange, TextSize,
};
use text_edit::TextEdit;
use crate::{
completions::postfix::format_like::add_format_like_completions,

View file

@ -20,7 +20,6 @@ use syntax::{
SyntaxKind::{self, *},
SyntaxToken, TextRange, TextSize, T,
};
use text_edit::Indel;
use crate::{
context::analysis::{expand_and_analyze, AnalysisResult},
@ -684,8 +683,7 @@ impl<'a> CompletionContext<'a> {
// actual completion.
let file_with_fake_ident = {
let parse = db.parse(file_id);
let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned());
parse.reparse(&edit, file_id.edition()).tree()
parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, file_id.edition()).tree()
};
// always pick the token to the immediate left of the cursor, as that is what we are actually

View file

@ -3,6 +3,7 @@
use std::{fmt, mem};
use hir::Mutability;
use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap,
SymbolKind,
@ -11,7 +12,6 @@ use itertools::Itertools;
use smallvec::SmallVec;
use stdx::{impl_from, never};
use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
use text_edit::TextEdit;
use crate::{
context::{CompletionContext, PathCompletionCtx},
@ -426,7 +426,7 @@ impl CompletionItem {
self.lookup.as_str()
}
pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> {
pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionRelevance)> {
// Relevance of the ref match should be the same as the original
// match, but with exact type match set because self.ref_match
// is only set if there is an exact type match.
@ -436,7 +436,10 @@ impl CompletionItem {
self.ref_match.map(|(mutability, offset)| {
(
format!("&{}{}", mutability.as_keyword_for_ref(), self.label),
text_edit::Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
ide_db::text_edit::Indel::insert(
offset,
format!("&{}", mutability.as_keyword_for_ref()),
),
relevance,
)
})

View file

@ -10,16 +10,17 @@ mod snippet;
#[cfg(test)]
mod tests;
use ide_db::text_edit::TextEdit;
use ide_db::{
helpers::mod_path_to_ast,
imports::{
import_assets::NameToImport,
insert_use::{self, ImportScope},
},
items_locator, FilePosition, RootDatabase,
items_locator,
syntax_helpers::tree_diff::diff,
FilePosition, RootDatabase,
};
use syntax::algo;
use text_edit::TextEdit;
use crate::{
completions::Completions,
@ -297,6 +298,6 @@ pub fn resolve_completion_edits(
}
});
algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
Some(vec![import_insert.finish()])
}

View file

@ -11,6 +11,7 @@ pub(crate) mod union_literal;
pub(crate) mod variant;
use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type};
use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::{Documentation, HasDocs},
helpers::item_name,
@ -18,7 +19,6 @@ use ide_db::{
RootDatabase, SnippetCap, SymbolKind,
};
use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
use text_edit::TextEdit;
use crate::{
context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext},

View file

@ -663,6 +663,7 @@ mod cfg {
ba dbg
ba opt_level
ba test
ba true
"#]],
);
check(
@ -674,6 +675,7 @@ mod cfg {
ba dbg
ba opt_level
ba test
ba true
"#]],
);
}

View file

@ -35,7 +35,6 @@ parser.workspace = true
profile.workspace = true
stdx.workspace = true
syntax.workspace = true
text-edit.workspace = true
span.workspace = true
# ide should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.

View file

@ -100,16 +100,19 @@ impl RootDatabase {
hir::db::ConstEvalQuery
hir::db::ConstEvalStaticQuery
hir::db::ConstParamTyQuery
hir::db::DynCompatibilityOfTraitQuery
hir::db::FieldTypesQuery
hir::db::FnDefDatumQuery
hir::db::FnDefVarianceQuery
hir::db::GenericDefaultsQuery
hir::db::GenericPredicatesForParamQuery
hir::db::GenericPredicatesQuery
hir::db::GenericPredicatesWithoutParentQuery
hir::db::ImplDatumQuery
hir::db::ImplSelfTyQuery
hir::db::ImplTraitQuery
hir::db::IncoherentInherentImplCratesQuery
hir::db::InferQuery
hir::db::InherentImplsInBlockQuery
hir::db::InherentImplsInCrateQuery
hir::db::InternCallableDefQuery
@ -119,7 +122,12 @@ impl RootDatabase {
hir::db::InternLifetimeParamIdQuery
hir::db::InternTypeOrConstParamIdQuery
hir::db::LayoutOfAdtQuery
hir::db::LayoutOfTyQuery
hir::db::LookupImplMethodQuery
hir::db::MirBodyForClosureQuery
hir::db::MirBodyQuery
hir::db::MonomorphizedMirBodyForClosureQuery
hir::db::MonomorphizedMirBodyQuery
hir::db::ProgramClausesForChalkEnvQuery
hir::db::ReturnTypeImplTraitsQuery
hir::db::TargetDataLayoutQuery
@ -128,13 +136,16 @@ impl RootDatabase {
hir::db::TraitImplsInBlockQuery
hir::db::TraitImplsInCrateQuery
hir::db::TraitImplsInDepsQuery
hir::db::TraitSolveQuery
hir::db::TyQuery
hir::db::TypeAliasImplTraitsQuery
hir::db::ValueTyQuery
// DefDatabase
hir::db::AttrsQuery
hir::db::BlockDefMapQuery
hir::db::BlockItemTreeQuery
hir::db::BlockItemTreeWithSourceMapQuery
hir::db::BodyQuery
hir::db::BodyWithSourceMapQuery
hir::db::ConstDataQuery
@ -145,17 +156,21 @@ impl RootDatabase {
hir::db::CrateSupportsNoStdQuery
hir::db::EnumDataQuery
hir::db::EnumVariantDataWithDiagnosticsQuery
hir::db::ExpandProcAttrMacrosQuery
hir::db::ExprScopesQuery
hir::db::ExternCrateDeclDataQuery
hir::db::FieldVisibilitiesQuery
hir::db::FieldsAttrsQuery
hir::db::FieldsAttrsSourceMapQuery
hir::db::FileItemTreeQuery
hir::db::FileItemTreeWithSourceMapQuery
hir::db::FunctionDataQuery
hir::db::FunctionVisibilityQuery
hir::db::GenericParamsQuery
hir::db::GenericParamsWithSourceMapQuery
hir::db::ImplDataWithDiagnosticsQuery
hir::db::ImportMapQuery
hir::db::IncludeMacroInvocQuery
hir::db::InternAnonymousConstQuery
hir::db::InternBlockQuery
hir::db::InternConstQuery
@ -177,7 +192,9 @@ impl RootDatabase {
hir::db::InternUseQuery
hir::db::LangItemQuery
hir::db::Macro2DataQuery
hir::db::MacroDefQuery
hir::db::MacroRulesDataQuery
hir::db::NotableTraitsInDepsQuery
hir::db::ProcMacroDataQuery
hir::db::StaticDataQuery
hir::db::StructDataWithDiagnosticsQuery
@ -212,6 +229,7 @@ impl RootDatabase {
hir::db::MacroArgQuery
hir::db::ParseMacroExpansionErrorQuery
hir::db::ParseMacroExpansionQuery
hir::db::ProcMacroSpanQuery
hir::db::ProcMacrosQuery
hir::db::RealSpanMapQuery
@ -220,7 +238,9 @@ impl RootDatabase {
// SourceDatabase
base_db::ParseQuery
base_db::ParseErrorsQuery
base_db::CrateGraphQuery
base_db::CrateWorkspaceDataQuery
// SourceDatabaseExt
base_db::FileTextQuery

View file

@ -5,14 +5,17 @@
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
use crate::documentation::{Documentation, HasDocs};
use crate::famous_defs::FamousDefs;
use crate::RootDatabase;
use arrayvec::ArrayVec;
use either::Either;
use hir::{
Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro,
Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule,
Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
};
use span::Edition;
use stdx::{format_to, impl_from};
@ -21,10 +24,6 @@ use syntax::{
match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
};
use crate::documentation::{Documentation, HasDocs};
use crate::famous_defs::FamousDefs;
use crate::RootDatabase;
// FIXME: a more precise name would probably be `Symbol`?
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum Definition {
@ -179,7 +178,19 @@ impl Definition {
Definition::Static(it) => it.docs(db),
Definition::Trait(it) => it.docs(db),
Definition::TraitAlias(it) => it.docs(db),
Definition::TypeAlias(it) => it.docs(db),
Definition::TypeAlias(it) => {
it.docs(db).or_else(|| {
// docs are missing, try to fall back to the docs of the aliased item.
let adt = it.ty(db).as_adt()?;
let docs = adt.docs(db)?;
let docs = format!(
"*This is the documentation for* `{}`\n\n{}",
adt.display(db, edition),
docs.as_str()
);
Some(Documentation::new(docs))
})
}
Definition::BuiltinType(it) => {
famous_defs.and_then(|fd| {
// std exposes prim_{} modules with docstrings on the root to document the builtins
@ -319,6 +330,8 @@ impl IdentClass {
.map(IdentClass::NameClass)
.or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
},
ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
@ -372,6 +385,9 @@ impl IdentClass {
| OperatorClass::Index(func)
| OperatorClass::Try(func),
) => res.push(Definition::Function(func)),
IdentClass::Operator(OperatorClass::Range(struct0)) => {
res.push(Definition::Adt(Adt::Struct(struct0)))
}
}
res
}
@ -546,6 +562,7 @@ impl NameClass {
#[derive(Debug)]
pub enum OperatorClass {
Range(Struct),
Await(Function),
Prefix(Function),
Index(Function),
@ -554,6 +571,20 @@ pub enum OperatorClass {
}
impl OperatorClass {
pub fn classify_range_pat(
sema: &Semantics<'_, RootDatabase>,
range_pat: &ast::RangePat,
) -> Option<OperatorClass> {
sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
}
pub fn classify_range_expr(
sema: &Semantics<'_, RootDatabase>,
range_expr: &ast::RangeExpr,
) -> Option<OperatorClass> {
sema.resolve_range_expr(range_expr).map(OperatorClass::Range)
}
pub fn classify_await(
sema: &Semantics<'_, RootDatabase>,
await_expr: &ast::AwaitExpr,

View file

@ -5,11 +5,11 @@ use hir::{
resolve_doc_path_on, sym, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile,
};
use itertools::Itertools;
use span::{TextRange, TextSize};
use syntax::{
ast::{self, IsString},
AstToken,
};
use text_edit::{TextRange, TextSize};
/// Holds documentation
#[derive(Debug, Clone, PartialEq, Eq, Hash)]

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