mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-25 11:17:13 +00:00
commit
e918b131f3
3
.github/workflows/rustc-pull.yml
vendored
3
.github/workflows/rustc-pull.yml
vendored
@ -11,10 +11,11 @@ jobs:
|
||||
if: github.repository == 'rust-lang/rust-analyzer'
|
||||
uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
|
||||
with:
|
||||
github-app-id: ${{ vars.APP_CLIENT_ID }}
|
||||
zulip-stream-id: 185405
|
||||
zulip-bot-email: "rust-analyzer-ci-bot@rust-lang.zulipchat.com"
|
||||
pr-base-branch: master
|
||||
branch-name: rustc-pull
|
||||
secrets:
|
||||
zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github-app-secret: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
116
Cargo.lock
generated
116
Cargo.lock
generated
@ -23,6 +23,12 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
@ -44,6 +50,15 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@ -119,6 +134,12 @@ version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.10"
|
||||
@ -287,6 +308,40 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "countme"
|
||||
version = "3.0.1"
|
||||
@ -308,6 +363,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
@ -565,6 +626,15 @@ version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
@ -591,6 +661,20 @@ dependencies = [
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"spin",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
@ -1561,6 +1645,17 @@ version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "postcard"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"heapless",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
@ -1608,6 +1703,7 @@ dependencies = [
|
||||
"ra-ap-rustc_lexer 0.123.0",
|
||||
"span",
|
||||
"syntax-bridge",
|
||||
"temp-dir",
|
||||
"tt",
|
||||
]
|
||||
|
||||
@ -1615,6 +1711,8 @@ dependencies = [
|
||||
name = "proc-macro-srv-cli"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"postcard",
|
||||
"proc-macro-api",
|
||||
"proc-macro-srv",
|
||||
"tt",
|
||||
@ -1991,6 +2089,15 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
@ -2208,6 +2315,15 @@ dependencies = [
|
||||
"vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -206,6 +206,7 @@ impl EditionedFileId {
|
||||
|
||||
#[salsa_macros::input(debug)]
|
||||
pub struct FileText {
|
||||
#[returns(ref)]
|
||||
pub text: Arc<str>,
|
||||
pub file_id: vfs::FileId,
|
||||
}
|
||||
@ -357,7 +358,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFil
|
||||
let _p = tracing::info_span!("parse", ?file_id).entered();
|
||||
let (file_id, edition) = file_id.unpack(db.as_dyn_database());
|
||||
let text = db.file_text(file_id).text(db);
|
||||
ast::SourceFile::parse(&text, edition)
|
||||
ast::SourceFile::parse(text, edition)
|
||||
}
|
||||
|
||||
fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> {
|
||||
|
@ -134,10 +134,10 @@ fn next_cfg_expr<S: Copy>(it: &mut tt::iter::TtIter<'_, S>) -> Option<CfgExpr> {
|
||||
};
|
||||
|
||||
// Eat comma separator
|
||||
if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = it.peek() {
|
||||
if punct.char == ',' {
|
||||
it.next();
|
||||
}
|
||||
if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = it.peek()
|
||||
&& punct.char == ','
|
||||
{
|
||||
it.next();
|
||||
}
|
||||
Some(ret)
|
||||
}
|
||||
|
@ -377,10 +377,10 @@ fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option<ReprOptions> {
|
||||
let mut align = None;
|
||||
if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() {
|
||||
tts.next();
|
||||
if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() {
|
||||
if let Ok(a) = lit.symbol.as_str().parse() {
|
||||
align = Align::from_bytes(a).ok();
|
||||
}
|
||||
if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next()
|
||||
&& let Ok(a) = lit.symbol.as_str().parse()
|
||||
{
|
||||
align = Align::from_bytes(a).ok();
|
||||
}
|
||||
}
|
||||
ReprOptions { align, ..Default::default() }
|
||||
|
@ -1487,13 +1487,13 @@ impl ExprCollector<'_> {
|
||||
ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
|
||||
ast::Expr::ParenExpr(e) => {
|
||||
// We special-case `(..)` for consistency with patterns.
|
||||
if let Some(ast::Expr::RangeExpr(range)) = e.expr() {
|
||||
if range.is_range_full() {
|
||||
return Some(self.alloc_pat_from_expr(
|
||||
Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
|
||||
syntax_ptr,
|
||||
));
|
||||
}
|
||||
if let Some(ast::Expr::RangeExpr(range)) = e.expr()
|
||||
&& range.is_range_full()
|
||||
{
|
||||
return Some(self.alloc_pat_from_expr(
|
||||
Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
|
||||
syntax_ptr,
|
||||
));
|
||||
}
|
||||
return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
|
||||
}
|
||||
@ -2569,19 +2569,18 @@ impl ExprCollector<'_> {
|
||||
}
|
||||
}
|
||||
RibKind::MacroDef(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 labels from before its declaration.
|
||||
// Therefore, if we got to the rib of its declaration, give up its hygiene
|
||||
// and use its parent expansion.
|
||||
if let Some((parent_ctx, label_macro_id)) = hygiene_info
|
||||
&& label_macro_id == **macro_id
|
||||
{
|
||||
// A macro is allowed to refer to labels from before its declaration.
|
||||
// Therefore, if we got to the rib of its declaration, give up its hygiene
|
||||
// and use its parent expansion.
|
||||
|
||||
hygiene_id =
|
||||
HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db));
|
||||
hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| {
|
||||
let expansion = self.db.lookup_intern_macro_call(expansion.into());
|
||||
(parent_ctx.parent(self.db), expansion.def)
|
||||
});
|
||||
}
|
||||
hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db));
|
||||
hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| {
|
||||
let expansion = self.db.lookup_intern_macro_call(expansion.into());
|
||||
(parent_ctx.parent(self.db), expansion.def)
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -259,10 +259,10 @@ impl ExprCollector<'_> {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(operand_idx) = operand_idx {
|
||||
if let Some(position_span) = to_span(arg.position_span) {
|
||||
mappings.push((position_span, operand_idx));
|
||||
}
|
||||
if let Some(operand_idx) = operand_idx
|
||||
&& let Some(position_span) = to_span(arg.position_span)
|
||||
{
|
||||
mappings.push((position_span, operand_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,16 +211,17 @@ pub(super) fn lower_path(
|
||||
// Basically, even in rustc it is quite hacky:
|
||||
// https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
|
||||
// We follow what it did anyway :)
|
||||
if segments.len() == 1 && kind == PathKind::Plain {
|
||||
if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
||||
let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range());
|
||||
if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db) {
|
||||
if collector.db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner {
|
||||
kind = match resolve_crate_root(collector.db, syn_ctxt) {
|
||||
Some(crate_root) => PathKind::DollarCrate(crate_root),
|
||||
None => PathKind::Crate,
|
||||
}
|
||||
}
|
||||
if segments.len() == 1
|
||||
&& kind == PathKind::Plain
|
||||
&& let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast)
|
||||
{
|
||||
let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range());
|
||||
if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db)
|
||||
&& collector.db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner
|
||||
{
|
||||
kind = match resolve_crate_root(collector.db, syn_ctxt) {
|
||||
Some(crate_root) => PathKind::DollarCrate(crate_root),
|
||||
None => PathKind::Crate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -900,14 +900,12 @@ impl Printer<'_> {
|
||||
let field_name = arg.name.display(self.db, edition).to_string();
|
||||
|
||||
let mut same_name = false;
|
||||
if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] {
|
||||
if let Binding { name, mode: BindingAnnotation::Unannotated, .. } =
|
||||
if let Pat::Bind { id, subpat: None } = &self.store[arg.pat]
|
||||
&& let Binding { name, mode: BindingAnnotation::Unannotated, .. } =
|
||||
&self.store.assert_expr_only().bindings[*id]
|
||||
{
|
||||
if name.as_str() == field_name {
|
||||
same_name = true;
|
||||
}
|
||||
}
|
||||
&& name.as_str() == field_name
|
||||
{
|
||||
same_name = true;
|
||||
}
|
||||
|
||||
w!(p, "{}", field_name);
|
||||
|
@ -107,11 +107,11 @@ struct FindPathCtx<'db> {
|
||||
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
|
||||
fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
|
||||
// - if the item is a module, jump straight to module search
|
||||
if !ctx.is_std_item {
|
||||
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
|
||||
return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
|
||||
.map(|choice| choice.path);
|
||||
}
|
||||
if !ctx.is_std_item
|
||||
&& let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item
|
||||
{
|
||||
return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
|
||||
.map(|choice| choice.path);
|
||||
}
|
||||
|
||||
let may_be_in_scope = match ctx.prefix {
|
||||
@ -226,15 +226,15 @@ fn find_path_for_module(
|
||||
}
|
||||
|
||||
// - if the module can be referenced as self, super or crate, do that
|
||||
if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) {
|
||||
if ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate {
|
||||
return Some(Choice {
|
||||
path: ModPath::from_segments(kind, None),
|
||||
path_text_len: path_kind_len(kind),
|
||||
stability: Stable,
|
||||
prefer_due_to_prelude: false,
|
||||
});
|
||||
}
|
||||
if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from)
|
||||
&& (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate)
|
||||
{
|
||||
return Some(Choice {
|
||||
path: ModPath::from_segments(kind, None),
|
||||
path_text_len: path_kind_len(kind),
|
||||
stability: Stable,
|
||||
prefer_due_to_prelude: false,
|
||||
});
|
||||
}
|
||||
|
||||
// - if the module is in the prelude, return it by that path
|
||||
@ -604,29 +604,29 @@ fn find_local_import_locations(
|
||||
&def_map[module.local_id]
|
||||
};
|
||||
|
||||
if let Some((name, vis, declared)) = data.scope.name_of(item) {
|
||||
if vis.is_visible_from(db, from) {
|
||||
let is_pub_or_explicit = match vis {
|
||||
Visibility::Module(_, VisibilityExplicitness::Explicit) => {
|
||||
cov_mark::hit!(explicit_private_imports);
|
||||
true
|
||||
}
|
||||
Visibility::Module(_, VisibilityExplicitness::Implicit) => {
|
||||
cov_mark::hit!(discount_private_imports);
|
||||
false
|
||||
}
|
||||
Visibility::PubCrate(_) => true,
|
||||
Visibility::Public => true,
|
||||
};
|
||||
|
||||
// Ignore private imports unless they are explicit. these could be used if we are
|
||||
// in a submodule of this module, but that's usually not
|
||||
// what the user wants; and if this module can import
|
||||
// the item and we're a submodule of it, so can we.
|
||||
// Also this keeps the cached data smaller.
|
||||
if declared || is_pub_or_explicit {
|
||||
cb(visited_modules, name, module);
|
||||
if let Some((name, vis, declared)) = data.scope.name_of(item)
|
||||
&& vis.is_visible_from(db, from)
|
||||
{
|
||||
let is_pub_or_explicit = match vis {
|
||||
Visibility::Module(_, VisibilityExplicitness::Explicit) => {
|
||||
cov_mark::hit!(explicit_private_imports);
|
||||
true
|
||||
}
|
||||
Visibility::Module(_, VisibilityExplicitness::Implicit) => {
|
||||
cov_mark::hit!(discount_private_imports);
|
||||
false
|
||||
}
|
||||
Visibility::PubCrate(_) => true,
|
||||
Visibility::Public => true,
|
||||
};
|
||||
|
||||
// Ignore private imports unless they are explicit. these could be used if we are
|
||||
// in a submodule of this module, but that's usually not
|
||||
// what the user wants; and if this module can import
|
||||
// the item and we're a submodule of it, so can we.
|
||||
// Also this keeps the cached data smaller.
|
||||
if declared || is_pub_or_explicit {
|
||||
cb(visited_modules, name, module);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,12 +510,11 @@ impl ItemScope {
|
||||
id: AttrId,
|
||||
idx: usize,
|
||||
) {
|
||||
if let Some(derives) = self.derive_macros.get_mut(&adt) {
|
||||
if let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
|
||||
if let Some(derives) = self.derive_macros.get_mut(&adt)
|
||||
&& let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
|
||||
derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id)
|
||||
{
|
||||
derive_call_ids[idx] = Some(call);
|
||||
}
|
||||
{
|
||||
derive_call_ids[idx] = Some(call);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,12 +83,12 @@ impl<'a> Ctx<'a> {
|
||||
.flat_map(|item| self.lower_mod_item(&item))
|
||||
.collect();
|
||||
|
||||
if let Some(ast::Expr::MacroExpr(tail_macro)) = stmts.expr() {
|
||||
if let Some(call) = tail_macro.macro_call() {
|
||||
cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
if let Some(ast::Expr::MacroExpr(tail_macro)) = stmts.expr()
|
||||
&& let Some(call) = tail_macro.macro_call()
|
||||
{
|
||||
cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,12 +112,11 @@ impl<'a> Ctx<'a> {
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() {
|
||||
if let Some(call) = expr.macro_call() {
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
}
|
||||
if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr()
|
||||
&& let Some(call) = expr.macro_call()
|
||||
&& let Some(mod_item) = self.lower_mod_item(&call.into())
|
||||
{
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
self.tree.vis.arena = self.visibilities.into_iter().collect();
|
||||
self.tree.top_level = self.top_level.into_boxed_slice();
|
||||
|
@ -218,10 +218,10 @@ pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option
|
||||
|
||||
for (_, module_data) in crate_def_map.modules() {
|
||||
for def in module_data.scope.declarations() {
|
||||
if let ModuleDefId::TraitId(trait_) = def {
|
||||
if db.attrs(trait_.into()).has_doc_notable_trait() {
|
||||
traits.push(trait_);
|
||||
}
|
||||
if let ModuleDefId::TraitId(trait_) = def
|
||||
&& db.attrs(trait_.into()).has_doc_notable_trait()
|
||||
{
|
||||
traits.push(trait_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,46 +221,42 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(src) = src {
|
||||
if let Some(file_id) = src.file_id.macro_file() {
|
||||
if let MacroKind::Derive
|
||||
| MacroKind::DeriveBuiltIn
|
||||
| MacroKind::Attr
|
||||
| MacroKind::AttrBuiltIn = file_id.kind(&db)
|
||||
{
|
||||
let call = file_id.call_node(&db);
|
||||
let mut show_spans = false;
|
||||
let mut show_ctxt = false;
|
||||
for comment in
|
||||
call.value.children_with_tokens().filter(|it| it.kind() == COMMENT)
|
||||
{
|
||||
show_spans |= comment.to_string().contains("+spans");
|
||||
show_ctxt |= comment.to_string().contains("+syntaxctxt");
|
||||
}
|
||||
let pp = pretty_print_macro_expansion(
|
||||
src.value,
|
||||
db.span_map(src.file_id).as_ref(),
|
||||
show_spans,
|
||||
show_ctxt,
|
||||
);
|
||||
format_to!(expanded_text, "\n{}", pp)
|
||||
}
|
||||
if let Some(src) = src
|
||||
&& let Some(file_id) = src.file_id.macro_file()
|
||||
&& let MacroKind::Derive
|
||||
| MacroKind::DeriveBuiltIn
|
||||
| MacroKind::Attr
|
||||
| MacroKind::AttrBuiltIn = file_id.kind(&db)
|
||||
{
|
||||
let call = file_id.call_node(&db);
|
||||
let mut show_spans = false;
|
||||
let mut show_ctxt = false;
|
||||
for comment in call.value.children_with_tokens().filter(|it| it.kind() == COMMENT) {
|
||||
show_spans |= comment.to_string().contains("+spans");
|
||||
show_ctxt |= comment.to_string().contains("+syntaxctxt");
|
||||
}
|
||||
let pp = pretty_print_macro_expansion(
|
||||
src.value,
|
||||
db.span_map(src.file_id).as_ref(),
|
||||
show_spans,
|
||||
show_ctxt,
|
||||
);
|
||||
format_to!(expanded_text, "\n{}", pp)
|
||||
}
|
||||
}
|
||||
|
||||
for impl_id in def_map[local_id].scope.impls() {
|
||||
let src = impl_id.lookup(&db).source(&db);
|
||||
if let Some(macro_file) = src.file_id.macro_file() {
|
||||
if let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db) {
|
||||
let pp = pretty_print_macro_expansion(
|
||||
src.value.syntax().clone(),
|
||||
db.span_map(macro_file.into()).as_ref(),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
format_to!(expanded_text, "\n{}", pp)
|
||||
}
|
||||
if let Some(macro_file) = src.file_id.macro_file()
|
||||
&& let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db)
|
||||
{
|
||||
let pp = pretty_print_macro_expansion(
|
||||
src.value.syntax().clone(),
|
||||
db.span_map(macro_file.into()).as_ref(),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
format_to!(expanded_text, "\n{}", pp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,20 +261,20 @@ impl<'db> DefCollector<'db> {
|
||||
|
||||
// Process other crate-level attributes.
|
||||
for attr in &*attrs {
|
||||
if let Some(cfg) = attr.cfg() {
|
||||
if self.cfg_options.check(&cfg) == Some(false) {
|
||||
process = false;
|
||||
break;
|
||||
}
|
||||
if let Some(cfg) = attr.cfg()
|
||||
&& self.cfg_options.check(&cfg) == Some(false)
|
||||
{
|
||||
process = false;
|
||||
break;
|
||||
}
|
||||
let Some(attr_name) = attr.path.as_ident() else { continue };
|
||||
|
||||
match () {
|
||||
() if *attr_name == sym::recursion_limit => {
|
||||
if let Some(limit) = attr.string_value() {
|
||||
if let Ok(limit) = limit.as_str().parse() {
|
||||
crate_data.recursion_limit = Some(limit);
|
||||
}
|
||||
if let Some(limit) = attr.string_value()
|
||||
&& let Ok(limit) = limit.as_str().parse()
|
||||
{
|
||||
crate_data.recursion_limit = Some(limit);
|
||||
}
|
||||
}
|
||||
() if *attr_name == sym::crate_type => {
|
||||
@ -1188,56 +1188,44 @@ impl<'db> DefCollector<'db> {
|
||||
// Multiple globs may import the same item and they may override visibility from
|
||||
// previously resolved globs. Handle overrides here and leave the rest to
|
||||
// `ItemScope::push_res_with_import()`.
|
||||
if let Some(def) = defs.types {
|
||||
if let Some(prev_def) = prev_defs.types {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_type(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// This import is being handled here, don't pass it down to
|
||||
// `ItemScope::push_res_with_import()`.
|
||||
defs.types = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_types(name, def.vis);
|
||||
}
|
||||
}
|
||||
if let Some(def) = defs.types
|
||||
&& let Some(prev_def) = prev_defs.types
|
||||
&& def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_type(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// This import is being handled here, don't pass it down to
|
||||
// `ItemScope::push_res_with_import()`.
|
||||
defs.types = None;
|
||||
self.def_map.modules[module_id].scope.update_visibility_types(name, def.vis);
|
||||
}
|
||||
|
||||
if let Some(def) = defs.values {
|
||||
if let Some(prev_def) = prev_defs.values {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_value(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.values = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_values(name, def.vis);
|
||||
}
|
||||
}
|
||||
if let Some(def) = defs.values
|
||||
&& let Some(prev_def) = prev_defs.values
|
||||
&& def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_value(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.values = None;
|
||||
self.def_map.modules[module_id].scope.update_visibility_values(name, def.vis);
|
||||
}
|
||||
|
||||
if let Some(def) = defs.macros {
|
||||
if let Some(prev_def) = prev_defs.macros {
|
||||
if def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_macro(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.macros = None;
|
||||
self.def_map.modules[module_id]
|
||||
.scope
|
||||
.update_visibility_macros(name, def.vis);
|
||||
}
|
||||
}
|
||||
if let Some(def) = defs.macros
|
||||
&& let Some(prev_def) = prev_defs.macros
|
||||
&& def.def == prev_def.def
|
||||
&& self.from_glob_import.contains_macro(module_id, name.clone())
|
||||
&& def.vis != prev_def.vis
|
||||
&& def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
|
||||
{
|
||||
changed = true;
|
||||
// See comment above.
|
||||
defs.macros = None;
|
||||
self.def_map.modules[module_id].scope.update_visibility_macros(name, def.vis);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,15 +1380,14 @@ impl<'db> DefCollector<'db> {
|
||||
Resolved::Yes
|
||||
};
|
||||
|
||||
if let Some(ident) = path.as_ident() {
|
||||
if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) {
|
||||
if helpers.iter().any(|(it, ..)| it == ident) {
|
||||
cov_mark::hit!(resolved_derive_helper);
|
||||
// Resolved to derive helper. Collect the item's attributes again,
|
||||
// starting after the derive helper.
|
||||
return recollect_without(self);
|
||||
}
|
||||
}
|
||||
if let Some(ident) = path.as_ident()
|
||||
&& let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id)
|
||||
&& helpers.iter().any(|(it, ..)| it == ident)
|
||||
{
|
||||
cov_mark::hit!(resolved_derive_helper);
|
||||
// Resolved to derive helper. Collect the item's attributes again,
|
||||
// starting after the derive helper.
|
||||
return recollect_without(self);
|
||||
}
|
||||
|
||||
let def = match resolver_def_id(path) {
|
||||
@ -1729,12 +1716,12 @@ impl ModCollector<'_, '_> {
|
||||
|
||||
let mut process_mod_item = |item: ModItemId| {
|
||||
let attrs = self.item_tree.attrs(db, krate, item.ast_id());
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if !self.is_cfg_enabled(&cfg) {
|
||||
let ast_id = item.ast_id().erase();
|
||||
self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
|
||||
return;
|
||||
}
|
||||
if let Some(cfg) = attrs.cfg()
|
||||
&& !self.is_cfg_enabled(&cfg)
|
||||
{
|
||||
let ast_id = item.ast_id().erase();
|
||||
self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
|
||||
@ -1871,14 +1858,13 @@ impl ModCollector<'_, '_> {
|
||||
if self.def_collector.def_map.block.is_none()
|
||||
&& self.def_collector.is_proc_macro
|
||||
&& self.module_id == DefMap::ROOT
|
||||
&& let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name)
|
||||
{
|
||||
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
|
||||
self.def_collector.export_proc_macro(
|
||||
proc_macro,
|
||||
InFile::new(self.file_id(), id),
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
self.def_collector.export_proc_macro(
|
||||
proc_macro,
|
||||
InFile::new(self.file_id(), id),
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
|
||||
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
|
||||
@ -2419,13 +2405,13 @@ impl ModCollector<'_, '_> {
|
||||
macro_id,
|
||||
&self.item_tree[mac.visibility],
|
||||
);
|
||||
if let Some(helpers) = helpers_opt {
|
||||
if self.def_collector.def_map.block.is_none() {
|
||||
Arc::get_mut(&mut self.def_collector.def_map.data)
|
||||
.unwrap()
|
||||
.exported_derives
|
||||
.insert(macro_id.into(), helpers);
|
||||
}
|
||||
if let Some(helpers) = helpers_opt
|
||||
&& self.def_collector.def_map.block.is_none()
|
||||
{
|
||||
Arc::get_mut(&mut self.def_collector.def_map.data)
|
||||
.unwrap()
|
||||
.exported_derives
|
||||
.insert(macro_id.into(), helpers);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,15 +228,15 @@ impl<'db> Resolver<'db> {
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
} else if let &GenericDefId::AdtId(adt) = def {
|
||||
if *first_name == sym::Self_ {
|
||||
return Some((
|
||||
TypeNs::AdtSelfType(adt),
|
||||
remaining_idx(),
|
||||
None,
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
} else if let &GenericDefId::AdtId(adt) = def
|
||||
&& *first_name == sym::Self_
|
||||
{
|
||||
return Some((
|
||||
TypeNs::AdtSelfType(adt),
|
||||
remaining_idx(),
|
||||
None,
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
return Some((
|
||||
@ -401,13 +401,13 @@ impl<'db> Resolver<'db> {
|
||||
handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id)
|
||||
}
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let &GenericDefId::ImplId(impl_) = def {
|
||||
if *first_name == sym::Self_ {
|
||||
return Some((
|
||||
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
if let &GenericDefId::ImplId(impl_) = def
|
||||
&& *first_name == sym::Self_
|
||||
{
|
||||
return Some((
|
||||
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
if let Some(id) = params.find_const_by_name(first_name, *def) {
|
||||
let val = ValueNs::GenericParam(id);
|
||||
@ -436,14 +436,14 @@ impl<'db> Resolver<'db> {
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
} else if let &GenericDefId::AdtId(adt) = def {
|
||||
if *first_name == sym::Self_ {
|
||||
let ty = TypeNs::AdtSelfType(adt);
|
||||
return Some((
|
||||
ResolveValueResult::Partial(ty, 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
} else if let &GenericDefId::AdtId(adt) = def
|
||||
&& *first_name == sym::Self_
|
||||
{
|
||||
let ty = TypeNs::AdtSelfType(adt);
|
||||
return Some((
|
||||
ResolveValueResult::Partial(ty, 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
let ty = TypeNs::GenericParam(id);
|
||||
@ -469,13 +469,14 @@ impl<'db> Resolver<'db> {
|
||||
// If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
|
||||
// to resolving to the primitive type, to allow this to still work in the presence of
|
||||
// `use core::u16;`.
|
||||
if path.kind == PathKind::Plain && n_segments > 1 {
|
||||
if let Some(builtin) = BuiltinType::by_name(first_name) {
|
||||
return Some((
|
||||
ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
if path.kind == PathKind::Plain
|
||||
&& n_segments > 1
|
||||
&& let Some(builtin) = BuiltinType::by_name(first_name)
|
||||
{
|
||||
return Some((
|
||||
ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
|
||||
None
|
||||
@ -660,12 +661,11 @@ impl<'db> Resolver<'db> {
|
||||
Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
|
||||
&Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => {
|
||||
let impl_data = db.impl_signature(impl_);
|
||||
if let Some(target_trait) = impl_data.target_trait {
|
||||
if let Some(TypeNs::TraitId(trait_)) = self
|
||||
if let Some(target_trait) = impl_data.target_trait
|
||||
&& let Some(TypeNs::TraitId(trait_)) = self
|
||||
.resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path])
|
||||
{
|
||||
traits.insert(trait_);
|
||||
}
|
||||
{
|
||||
traits.insert(trait_);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@ -918,17 +918,17 @@ fn handle_macro_def_scope(
|
||||
hygiene_info: &mut Option<(SyntaxContext, MacroDefId)>,
|
||||
macro_id: &MacroDefId,
|
||||
) {
|
||||
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.
|
||||
*hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db));
|
||||
*hygiene_info = parent_ctx.outer_expn(db).map(|expansion| {
|
||||
let expansion = db.lookup_intern_macro_call(expansion.into());
|
||||
(parent_ctx.parent(db), expansion.def)
|
||||
});
|
||||
}
|
||||
if let Some((parent_ctx, label_macro_id)) = hygiene_info
|
||||
&& 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.
|
||||
*hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db));
|
||||
*hygiene_info = parent_ctx.outer_expn(db).map(|expansion| {
|
||||
let expansion = db.lookup_intern_macro_call(expansion.into());
|
||||
(parent_ctx.parent(db), expansion.def)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,12 +555,11 @@ fn concat_expand(
|
||||
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
|
||||
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
|
||||
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
|
||||
if let TtElement::Subtree(subtree, subtree_iter) = &t {
|
||||
if let [tt::TokenTree::Leaf(tt)] = subtree_iter.remaining().flat_tokens() {
|
||||
if subtree.delimiter.kind == tt::DelimiterKind::Parenthesis {
|
||||
t = TtElement::Leaf(tt);
|
||||
}
|
||||
}
|
||||
if let TtElement::Subtree(subtree, subtree_iter) = &t
|
||||
&& let [tt::TokenTree::Leaf(tt)] = subtree_iter.remaining().flat_tokens()
|
||||
&& subtree.delimiter.kind == tt::DelimiterKind::Parenthesis
|
||||
{
|
||||
t = TtElement::Leaf(tt);
|
||||
}
|
||||
match t {
|
||||
TtElement::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => {
|
||||
@ -891,7 +890,7 @@ fn include_str_expand(
|
||||
};
|
||||
|
||||
let text = db.file_text(file_id.file_id(db));
|
||||
let text = &*text.text(db);
|
||||
let text = &**text.text(db);
|
||||
|
||||
ExpandResult::ok(quote!(call_site =>#text))
|
||||
}
|
||||
|
@ -334,10 +334,10 @@ where
|
||||
_ => Some(CfgExpr::Atom(CfgAtom::Flag(name))),
|
||||
},
|
||||
};
|
||||
if let Some(NodeOrToken::Token(element)) = iter.peek() {
|
||||
if element.kind() == syntax::T![,] {
|
||||
iter.next();
|
||||
}
|
||||
if let Some(NodeOrToken::Token(element)) = iter.peek()
|
||||
&& element.kind() == syntax::T![,]
|
||||
{
|
||||
iter.next();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -99,6 +99,16 @@ impl FileRange {
|
||||
pub fn into_file_id(self, db: &dyn ExpandDatabase) -> FileRangeWrapper<FileId> {
|
||||
FileRangeWrapper { file_id: self.file_id.file_id(db), range: self.range }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn file_text(self, db: &dyn ExpandDatabase) -> &triomphe::Arc<str> {
|
||||
db.file_text(self.file_id.file_id(db)).text(db)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn text(self, db: &dyn ExpandDatabase) -> &str {
|
||||
&self.file_text(db)[self.range]
|
||||
}
|
||||
}
|
||||
|
||||
/// `AstId` points to an AST node in any file.
|
||||
|
@ -280,8 +280,8 @@ pub(crate) fn fixup_syntax(
|
||||
}
|
||||
},
|
||||
ast::RecordExprField(it) => {
|
||||
if let Some(colon) = it.colon_token() {
|
||||
if it.name_ref().is_some() && it.expr().is_none() {
|
||||
if let Some(colon) = it.colon_token()
|
||||
&& it.name_ref().is_some() && it.expr().is_none() {
|
||||
append.insert(colon.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
sym: sym::__ra_fixup,
|
||||
@ -290,11 +290,10 @@ pub(crate) fn fixup_syntax(
|
||||
})
|
||||
]);
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::Path(it) => {
|
||||
if let Some(colon) = it.coloncolon_token() {
|
||||
if it.segment().is_none() {
|
||||
if let Some(colon) = it.coloncolon_token()
|
||||
&& it.segment().is_none() {
|
||||
append.insert(colon.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
sym: sym::__ra_fixup,
|
||||
@ -303,7 +302,6 @@ pub(crate) fn fixup_syntax(
|
||||
})
|
||||
]);
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::ClosureExpr(it) => {
|
||||
if it.body().is_none() {
|
||||
|
@ -365,12 +365,11 @@ impl HirFileId {
|
||||
HirFileId::FileId(id) => break id,
|
||||
HirFileId::MacroFile(file) => {
|
||||
let loc = db.lookup_intern_macro_call(file);
|
||||
if loc.def.is_include() {
|
||||
if let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind {
|
||||
if let Ok(it) = include_input_to_file_id(db, file, &eager.arg) {
|
||||
break it;
|
||||
}
|
||||
}
|
||||
if loc.def.is_include()
|
||||
&& let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind
|
||||
&& let Ok(it) = include_input_to_file_id(db, file, &eager.arg)
|
||||
{
|
||||
break it;
|
||||
}
|
||||
self = loc.kind.file_id();
|
||||
}
|
||||
@ -648,12 +647,11 @@ impl MacroCallLoc {
|
||||
db: &dyn ExpandDatabase,
|
||||
macro_call_id: MacroCallId,
|
||||
) -> Option<EditionedFileId> {
|
||||
if self.def.is_include() {
|
||||
if let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind {
|
||||
if let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg) {
|
||||
return Some(it);
|
||||
}
|
||||
}
|
||||
if self.def.is_include()
|
||||
&& let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind
|
||||
&& let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg)
|
||||
{
|
||||
return Some(it);
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -273,16 +273,17 @@ fn convert_path(
|
||||
// Basically, even in rustc it is quite hacky:
|
||||
// https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
|
||||
// We follow what it did anyway :)
|
||||
if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain {
|
||||
if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
||||
let syn_ctx = span_for_range(segment.syntax().text_range());
|
||||
if let Some(macro_call_id) = syn_ctx.outer_expn(db) {
|
||||
if db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner {
|
||||
mod_path.kind = match resolve_crate_root(db, syn_ctx) {
|
||||
Some(crate_root) => PathKind::DollarCrate(crate_root),
|
||||
None => PathKind::Crate,
|
||||
}
|
||||
}
|
||||
if mod_path.segments.len() == 1
|
||||
&& mod_path.kind == PathKind::Plain
|
||||
&& let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast)
|
||||
{
|
||||
let syn_ctx = span_for_range(segment.syntax().text_range());
|
||||
if let Some(macro_call_id) = syn_ctx.outer_expn(db)
|
||||
&& db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner
|
||||
{
|
||||
mod_path.kind = match resolve_crate_root(db, syn_ctx) {
|
||||
Some(crate_root) => PathKind::DollarCrate(crate_root),
|
||||
None => PathKind::Crate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,10 +197,11 @@ pub(crate) fn deref_by_trait(
|
||||
// effectively bump the MSRV of rust-analyzer to 1.84 due to 1.83 and below lacking the
|
||||
// blanked impl on `Deref`.
|
||||
#[expect(clippy::overly_complex_bool_expr)]
|
||||
if use_receiver_trait && false {
|
||||
if let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) {
|
||||
return Some(receiver);
|
||||
}
|
||||
if use_receiver_trait
|
||||
&& false
|
||||
&& let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate)
|
||||
{
|
||||
return Some(receiver);
|
||||
}
|
||||
// Old rustc versions might not have `Receiver` trait.
|
||||
// Fallback to `Deref` if they don't
|
||||
|
@ -309,11 +309,11 @@ impl TyBuilder<hir_def::AdtId> {
|
||||
if let Some(defaults) = defaults.get(self.vec.len()..) {
|
||||
for default_ty in defaults {
|
||||
// NOTE(skip_binders): we only check if the arg type is error type.
|
||||
if let Some(x) = default_ty.skip_binders().ty(Interner) {
|
||||
if x.is_unknown() {
|
||||
self.vec.push(fallback().cast(Interner));
|
||||
continue;
|
||||
}
|
||||
if let Some(x) = default_ty.skip_binders().ty(Interner)
|
||||
&& x.is_unknown()
|
||||
{
|
||||
self.vec.push(fallback().cast(Interner));
|
||||
continue;
|
||||
}
|
||||
// Each default can only depend on the previous parameters.
|
||||
self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
|
||||
|
@ -83,34 +83,34 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None })
|
||||
}
|
||||
fn discriminant_type(&self, ty: chalk_ir::Ty<Interner>) -> chalk_ir::Ty<Interner> {
|
||||
if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) {
|
||||
if let hir_def::AdtId::EnumId(e) = id.0 {
|
||||
let enum_data = self.db.enum_signature(e);
|
||||
let ty = enum_data.repr.unwrap_or_default().discr_type();
|
||||
return chalk_ir::TyKind::Scalar(match ty {
|
||||
hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed {
|
||||
true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize),
|
||||
false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize),
|
||||
},
|
||||
hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed {
|
||||
true => chalk_ir::Scalar::Int(match size {
|
||||
hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8,
|
||||
hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16,
|
||||
hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32,
|
||||
hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64,
|
||||
hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128,
|
||||
}),
|
||||
false => chalk_ir::Scalar::Uint(match size {
|
||||
hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8,
|
||||
hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16,
|
||||
hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32,
|
||||
hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64,
|
||||
hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128,
|
||||
}),
|
||||
},
|
||||
})
|
||||
.intern(Interner);
|
||||
}
|
||||
if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner)
|
||||
&& let hir_def::AdtId::EnumId(e) = id.0
|
||||
{
|
||||
let enum_data = self.db.enum_signature(e);
|
||||
let ty = enum_data.repr.unwrap_or_default().discr_type();
|
||||
return chalk_ir::TyKind::Scalar(match ty {
|
||||
hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed {
|
||||
true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize),
|
||||
false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize),
|
||||
},
|
||||
hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed {
|
||||
true => chalk_ir::Scalar::Int(match size {
|
||||
hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8,
|
||||
hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16,
|
||||
hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32,
|
||||
hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64,
|
||||
hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128,
|
||||
}),
|
||||
false => chalk_ir::Scalar::Uint(match size {
|
||||
hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8,
|
||||
hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16,
|
||||
hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32,
|
||||
hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64,
|
||||
hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128,
|
||||
}),
|
||||
},
|
||||
})
|
||||
.intern(Interner);
|
||||
}
|
||||
chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8)).intern(Interner)
|
||||
}
|
||||
@ -142,10 +142,10 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
) -> Option<chalk_ir::TyVariableKind> {
|
||||
if let TyKind::BoundVar(bv) = ty.kind(Interner) {
|
||||
let binders = binders.as_slice(Interner);
|
||||
if bv.debruijn == DebruijnIndex::INNERMOST {
|
||||
if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
|
||||
return Some(tk);
|
||||
}
|
||||
if bv.debruijn == DebruijnIndex::INNERMOST
|
||||
&& let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind
|
||||
{
|
||||
return Some(tk);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -342,10 +342,10 @@ pub(crate) fn eval_to_const(
|
||||
return c;
|
||||
}
|
||||
}
|
||||
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) {
|
||||
if let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) {
|
||||
return result;
|
||||
}
|
||||
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr)
|
||||
&& let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
unknown_const(infer[expr].clone())
|
||||
}
|
||||
|
@ -657,10 +657,10 @@ impl<'a> DeclValidator<'a> {
|
||||
}
|
||||
|
||||
fn is_trait_impl_container(&self, container_id: ItemContainerId) -> bool {
|
||||
if let ItemContainerId::ImplId(impl_id) = container_id {
|
||||
if self.db.impl_trait(impl_id).is_some() {
|
||||
return true;
|
||||
}
|
||||
if let ItemContainerId::ImplId(impl_id) = container_id
|
||||
&& self.db.impl_trait(impl_id).is_some()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
@ -528,15 +528,15 @@ impl FilterMapNextChecker {
|
||||
return None;
|
||||
}
|
||||
|
||||
if *function_id == self.next_function_id? {
|
||||
if let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id {
|
||||
let is_dyn_trait = self
|
||||
.prev_receiver_ty
|
||||
.as_ref()
|
||||
.is_some_and(|it| it.strip_references().dyn_trait().is_some());
|
||||
if *receiver_expr_id == prev_filter_map_expr_id && !is_dyn_trait {
|
||||
return Some(());
|
||||
}
|
||||
if *function_id == self.next_function_id?
|
||||
&& let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id
|
||||
{
|
||||
let is_dyn_trait = self
|
||||
.prev_receiver_ty
|
||||
.as_ref()
|
||||
.is_some_and(|it| it.strip_references().dyn_trait().is_some());
|
||||
if *receiver_expr_id == prev_filter_map_expr_id && !is_dyn_trait {
|
||||
return Some(());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,10 +382,10 @@ impl HirDisplay for Pat {
|
||||
let subpats = (0..num_fields).map(|i| {
|
||||
WriteWith(move |f| {
|
||||
let fid = LocalFieldId::from_raw((i as u32).into());
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
if p.field == fid {
|
||||
return p.pattern.hir_fmt(f);
|
||||
}
|
||||
if let Some(p) = subpatterns.get(i)
|
||||
&& p.field == fid
|
||||
{
|
||||
return p.pattern.hir_fmt(f);
|
||||
}
|
||||
if let Some(p) = subpatterns.iter().find(|p| p.field == fid) {
|
||||
p.pattern.hir_fmt(f)
|
||||
|
@ -272,10 +272,10 @@ impl<'db> UnsafeVisitor<'db> {
|
||||
if let Some(func) = callee.as_fn_def(self.db) {
|
||||
self.check_call(current, func);
|
||||
}
|
||||
if let TyKind::Function(fn_ptr) = callee.kind(Interner) {
|
||||
if fn_ptr.sig.safety == chalk_ir::Safety::Unsafe {
|
||||
self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall);
|
||||
}
|
||||
if let TyKind::Function(fn_ptr) = callee.kind(Interner)
|
||||
&& fn_ptr.sig.safety == chalk_ir::Safety::Unsafe
|
||||
{
|
||||
self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall);
|
||||
}
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
@ -346,12 +346,11 @@ impl<'db> UnsafeVisitor<'db> {
|
||||
Expr::Cast { .. } => self.inside_assignment = inside_assignment,
|
||||
Expr::Field { .. } => {
|
||||
self.inside_assignment = inside_assignment;
|
||||
if !inside_assignment {
|
||||
if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
|
||||
if !inside_assignment
|
||||
&& let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
|
||||
self.infer.field_resolution(current)
|
||||
{
|
||||
self.on_unsafe_op(current.into(), UnsafetyReason::UnionField);
|
||||
}
|
||||
{
|
||||
self.on_unsafe_op(current.into(), UnsafetyReason::UnionField);
|
||||
}
|
||||
}
|
||||
Expr::Unsafe { statements, .. } => {
|
||||
|
@ -608,48 +608,46 @@ impl HirDisplay for ProjectionTy {
|
||||
// if we are projection on a type parameter, check if the projection target has bounds
|
||||
// itself, if so, we render them directly as `impl Bound` instead of the less useful
|
||||
// `<Param as Trait>::Assoc`
|
||||
if !f.display_kind.is_source_code() {
|
||||
if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
|
||||
if !f.bounds_formatting_ctx.contains(self) {
|
||||
let db = f.db;
|
||||
let id = from_placeholder_idx(db, *idx);
|
||||
let generics = generics(db, id.parent);
|
||||
if !f.display_kind.is_source_code()
|
||||
&& let TyKind::Placeholder(idx) = self_ty.kind(Interner)
|
||||
&& !f.bounds_formatting_ctx.contains(self)
|
||||
{
|
||||
let db = f.db;
|
||||
let id = from_placeholder_idx(db, *idx);
|
||||
let generics = generics(db, id.parent);
|
||||
|
||||
let substs = generics.placeholder_subst(db);
|
||||
let bounds = db
|
||||
.generic_predicates(id.parent)
|
||||
.iter()
|
||||
.map(|pred| pred.clone().substitute(Interner, &substs))
|
||||
.filter(|wc| match wc.skip_binders() {
|
||||
WhereClause::Implemented(tr) => {
|
||||
matches!(
|
||||
tr.self_type_parameter(Interner).kind(Interner),
|
||||
TyKind::Alias(_)
|
||||
)
|
||||
}
|
||||
WhereClause::TypeOutlives(t) => {
|
||||
matches!(t.ty.kind(Interner), TyKind::Alias(_))
|
||||
}
|
||||
// We shouldn't be here if these exist
|
||||
WhereClause::AliasEq(_) => false,
|
||||
WhereClause::LifetimeOutlives(_) => false,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !bounds.is_empty() {
|
||||
return f.format_bounds_with(self.clone(), |f| {
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
f,
|
||||
"impl",
|
||||
Either::Left(
|
||||
&TyKind::Alias(AliasTy::Projection(self.clone()))
|
||||
.intern(Interner),
|
||||
),
|
||||
&bounds,
|
||||
SizedByDefault::NotSized,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
let substs = generics.placeholder_subst(db);
|
||||
let bounds = db
|
||||
.generic_predicates(id.parent)
|
||||
.iter()
|
||||
.map(|pred| pred.clone().substitute(Interner, &substs))
|
||||
.filter(|wc| {
|
||||
let ty = match wc.skip_binders() {
|
||||
WhereClause::Implemented(tr) => tr.self_type_parameter(Interner),
|
||||
WhereClause::TypeOutlives(t) => t.ty.clone(),
|
||||
// We shouldn't be here if these exist
|
||||
WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else {
|
||||
return false;
|
||||
};
|
||||
proj == self
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !bounds.is_empty() {
|
||||
return f.format_bounds_with(self.clone(), |f| {
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
f,
|
||||
"impl",
|
||||
Either::Left(
|
||||
&TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
|
||||
),
|
||||
&bounds,
|
||||
SizedByDefault::NotSized,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1860,18 +1858,13 @@ fn write_bounds_like_dyn_trait(
|
||||
write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
|
||||
f.end_location_link();
|
||||
if is_fn_trait {
|
||||
if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
|
||||
if let Some(args) =
|
||||
if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner)
|
||||
&& let Some(args) =
|
||||
params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
|
||||
{
|
||||
write!(f, "(")?;
|
||||
hir_fmt_generic_arguments(
|
||||
f,
|
||||
args.as_slice(Interner),
|
||||
self_.ty(Interner),
|
||||
)?;
|
||||
write!(f, ")")?;
|
||||
}
|
||||
{
|
||||
write!(f, "(")?;
|
||||
hir_fmt_generic_arguments(f, args.as_slice(Interner), self_.ty(Interner))?;
|
||||
write!(f, ")")?;
|
||||
}
|
||||
} else {
|
||||
let params = generic_args_sans_defaults(
|
||||
@ -1879,13 +1872,13 @@ fn write_bounds_like_dyn_trait(
|
||||
Some(trait_.into()),
|
||||
trait_ref.substitution.as_slice(Interner),
|
||||
);
|
||||
if let [self_, params @ ..] = params {
|
||||
if !params.is_empty() {
|
||||
write!(f, "<")?;
|
||||
hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
|
||||
// there might be assoc type bindings, so we leave the angle brackets open
|
||||
angle_open = true;
|
||||
}
|
||||
if let [self_, params @ ..] = params
|
||||
&& !params.is_empty()
|
||||
{
|
||||
write!(f, "<")?;
|
||||
hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
|
||||
// there might be assoc type bindings, so we leave the angle brackets open
|
||||
angle_open = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2443,11 +2436,11 @@ impl HirDisplayWithExpressionStore for Path {
|
||||
generic_args.args[0].hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
if let Some(ret) = generic_args.bindings[0].type_ref {
|
||||
if !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty()) {
|
||||
write!(f, " -> ")?;
|
||||
ret.hir_fmt(f, store)?;
|
||||
}
|
||||
if let Some(ret) = generic_args.bindings[0].type_ref
|
||||
&& !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty())
|
||||
{
|
||||
write!(f, " -> ")?;
|
||||
ret.hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
hir_def::expr_store::path::GenericArgsParentheses::No => {
|
||||
|
@ -136,16 +136,15 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
|
||||
let predicates = predicates.iter().map(|p| p.skip_binders().skip_binders().clone());
|
||||
elaborate_clause_supertraits(db, predicates).any(|pred| match pred {
|
||||
WhereClause::Implemented(trait_ref) => {
|
||||
if from_chalk_trait_id(trait_ref.trait_id) == sized {
|
||||
if let TyKind::BoundVar(it) =
|
||||
if from_chalk_trait_id(trait_ref.trait_id) == sized
|
||||
&& let TyKind::BoundVar(it) =
|
||||
*trait_ref.self_type_parameter(Interner).kind(Interner)
|
||||
{
|
||||
// Since `generic_predicates` is `Binder<Binder<..>>`, the `DebrujinIndex` of
|
||||
// self-parameter is `1`
|
||||
return it
|
||||
.index_if_bound_at(DebruijnIndex::ONE)
|
||||
.is_some_and(|idx| idx == trait_self_param_idx);
|
||||
}
|
||||
{
|
||||
// Since `generic_predicates` is `Binder<Binder<..>>`, the `DebrujinIndex` of
|
||||
// self-parameter is `1`
|
||||
return it
|
||||
.index_if_bound_at(DebruijnIndex::ONE)
|
||||
.is_some_and(|idx| idx == trait_self_param_idx);
|
||||
}
|
||||
false
|
||||
}
|
||||
@ -401,10 +400,10 @@ where
|
||||
cb(MethodViolationCode::ReferencesSelfOutput)?;
|
||||
}
|
||||
|
||||
if !func_data.is_async() {
|
||||
if let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig) {
|
||||
cb(mvc)?;
|
||||
}
|
||||
if !func_data.is_async()
|
||||
&& let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig)
|
||||
{
|
||||
cb(mvc)?;
|
||||
}
|
||||
|
||||
let generic_params = db.generic_params(func.into());
|
||||
|
@ -902,12 +902,12 @@ impl<'db> InferenceContext<'db> {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic {
|
||||
if let Some(ty) = field_with_same_name {
|
||||
*ty = table.resolve_completely(ty.clone());
|
||||
if ty.contains_unknown() {
|
||||
*field_with_same_name = None;
|
||||
}
|
||||
if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic
|
||||
&& let Some(ty) = field_with_same_name
|
||||
{
|
||||
*ty = table.resolve_completely(ty.clone());
|
||||
if ty.contains_unknown() {
|
||||
*field_with_same_name = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1010,12 +1010,12 @@ impl<'db> InferenceContext<'db> {
|
||||
param_tys.push(va_list_ty);
|
||||
}
|
||||
let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var()));
|
||||
if let Some(self_param) = self.body.self_param {
|
||||
if let Some(ty) = param_tys.next() {
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
self.write_binding_ty(self_param, ty);
|
||||
}
|
||||
if let Some(self_param) = self.body.self_param
|
||||
&& let Some(ty) = param_tys.next()
|
||||
{
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
self.write_binding_ty(self_param, ty);
|
||||
}
|
||||
let mut tait_candidates = FxHashSet::default();
|
||||
for (ty, pat) in param_tys.zip(&*self.body.params) {
|
||||
@ -1199,20 +1199,19 @@ impl<'db> InferenceContext<'db> {
|
||||
) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
let ty = self.table.resolve_ty_shallow(ty);
|
||||
|
||||
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
|
||||
if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
|
||||
if let TyKind::OpaqueType(id, _) = ty.kind(Interner)
|
||||
&& let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
|
||||
self.db.lookup_intern_impl_trait_id((*id).into())
|
||||
{
|
||||
let loc = self.db.lookup_intern_type_alias(alias_id);
|
||||
match loc.container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
self.assocs.insert(*id, (impl_id, ty.clone()));
|
||||
}
|
||||
ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => {
|
||||
self.non_assocs.insert(*id, ty.clone());
|
||||
}
|
||||
_ => {}
|
||||
{
|
||||
let loc = self.db.lookup_intern_type_alias(alias_id);
|
||||
match loc.container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
self.assocs.insert(*id, (impl_id, ty.clone()));
|
||||
}
|
||||
ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => {
|
||||
self.non_assocs.insert(*id, ty.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,26 +233,25 @@ impl CastCheck {
|
||||
F: FnMut(ExprId, Vec<Adjustment>),
|
||||
{
|
||||
// Mutability order is opposite to rustc. `Mut < Not`
|
||||
if m_expr <= m_cast {
|
||||
if let TyKind::Array(ety, _) = t_expr.kind(Interner) {
|
||||
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
||||
let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner);
|
||||
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes)
|
||||
{
|
||||
apply_adjustments(self.source_expr, adj);
|
||||
} else {
|
||||
never!(
|
||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||
self.expr_ty,
|
||||
array_ptr_type
|
||||
);
|
||||
}
|
||||
if m_expr <= m_cast
|
||||
&& let TyKind::Array(ety, _) = t_expr.kind(Interner)
|
||||
{
|
||||
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
||||
let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner);
|
||||
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes) {
|
||||
apply_adjustments(self.source_expr, adj);
|
||||
} else {
|
||||
never!(
|
||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||
self.expr_ty,
|
||||
array_ptr_type
|
||||
);
|
||||
}
|
||||
|
||||
// This is a less strict condition than rustc's `demand_eqtype`,
|
||||
// but false negative is better than false positive
|
||||
if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
// This is a less strict condition than rustc's `demand_eqtype`,
|
||||
// but false negative is better than false positive
|
||||
if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,12 +176,12 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
|
||||
// Deduction based on the expected `dyn Fn` is done separately.
|
||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
|
||||
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
||||
let expected_sig_ty = TyKind::Function(sig).intern(Interner);
|
||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner)
|
||||
&& let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty)
|
||||
{
|
||||
let expected_sig_ty = TyKind::Function(sig).intern(Interner);
|
||||
|
||||
self.unify(sig_ty, &expected_sig_ty);
|
||||
}
|
||||
self.unify(sig_ty, &expected_sig_ty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,14 +208,13 @@ impl InferenceContext<'_> {
|
||||
alias: AliasTy::Projection(projection_ty),
|
||||
ty: projected_ty,
|
||||
}) = bound.skip_binders()
|
||||
{
|
||||
if let Some(sig) = self.deduce_sig_from_projection(
|
||||
&& let Some(sig) = self.deduce_sig_from_projection(
|
||||
closure_kind,
|
||||
projection_ty,
|
||||
projected_ty,
|
||||
) {
|
||||
return Some(sig);
|
||||
}
|
||||
)
|
||||
{
|
||||
return Some(sig);
|
||||
}
|
||||
None
|
||||
});
|
||||
@ -254,55 +253,44 @@ impl InferenceContext<'_> {
|
||||
let mut expected_kind = None;
|
||||
|
||||
for clause in elaborate_clause_supertraits(self.db, clauses.rev()) {
|
||||
if expected_sig.is_none() {
|
||||
if let WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(projection),
|
||||
ty,
|
||||
}) = &clause
|
||||
{
|
||||
let inferred_sig =
|
||||
self.deduce_sig_from_projection(closure_kind, projection, ty);
|
||||
// Make sure that we didn't infer a signature that mentions itself.
|
||||
// This can happen when we elaborate certain supertrait bounds that
|
||||
// mention projections containing the `Self` type. See rust-lang/rust#105401.
|
||||
struct MentionsTy<'a> {
|
||||
expected_ty: &'a Ty,
|
||||
if expected_sig.is_none()
|
||||
&& let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) =
|
||||
&clause
|
||||
{
|
||||
let inferred_sig = self.deduce_sig_from_projection(closure_kind, projection, ty);
|
||||
// Make sure that we didn't infer a signature that mentions itself.
|
||||
// This can happen when we elaborate certain supertrait bounds that
|
||||
// mention projections containing the `Self` type. See rust-lang/rust#105401.
|
||||
struct MentionsTy<'a> {
|
||||
expected_ty: &'a Ty,
|
||||
}
|
||||
impl TypeVisitor<Interner> for MentionsTy<'_> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn interner(&self) -> Interner {
|
||||
Interner
|
||||
}
|
||||
impl TypeVisitor<Interner> for MentionsTy<'_> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn interner(&self) -> Interner {
|
||||
Interner
|
||||
}
|
||||
|
||||
fn as_dyn(
|
||||
&mut self,
|
||||
) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy>
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn visit_ty(
|
||||
&mut self,
|
||||
t: &Ty,
|
||||
db: chalk_ir::DebruijnIndex,
|
||||
) -> ControlFlow<()> {
|
||||
if t == self.expected_ty {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
t.super_visit_with(self, db)
|
||||
}
|
||||
}
|
||||
}
|
||||
if inferred_sig
|
||||
.visit_with(
|
||||
&mut MentionsTy { expected_ty },
|
||||
chalk_ir::DebruijnIndex::INNERMOST,
|
||||
)
|
||||
.is_continue()
|
||||
fn as_dyn(
|
||||
&mut self,
|
||||
) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy>
|
||||
{
|
||||
expected_sig = inferred_sig;
|
||||
self
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &Ty, db: chalk_ir::DebruijnIndex) -> ControlFlow<()> {
|
||||
if t == self.expected_ty {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
t.super_visit_with(self, db)
|
||||
}
|
||||
}
|
||||
}
|
||||
if inferred_sig
|
||||
.visit_with(&mut MentionsTy { expected_ty }, chalk_ir::DebruijnIndex::INNERMOST)
|
||||
.is_continue()
|
||||
{
|
||||
expected_sig = inferred_sig;
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,11 +605,10 @@ impl HirPlace {
|
||||
if let CaptureKind::ByRef(BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
|
||||
}) = current_capture
|
||||
&& self.projections[len..].contains(&ProjectionElem::Deref)
|
||||
{
|
||||
if self.projections[len..].contains(&ProjectionElem::Deref) {
|
||||
current_capture =
|
||||
CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture });
|
||||
}
|
||||
current_capture =
|
||||
CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture });
|
||||
}
|
||||
current_capture
|
||||
}
|
||||
@ -1076,12 +1063,11 @@ impl InferenceContext<'_> {
|
||||
Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
|
||||
Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared),
|
||||
};
|
||||
if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) {
|
||||
if let Some(place) =
|
||||
if let Some(place) = self.place_of_expr_without_adjust(tgt_expr)
|
||||
&& let Some(place) =
|
||||
apply_adjusts_to_place(&mut self.current_capture_span_stack, place, rest)
|
||||
{
|
||||
self.add_capture(place, capture_kind);
|
||||
}
|
||||
{
|
||||
self.add_capture(place, capture_kind);
|
||||
}
|
||||
self.walk_expr_with_adjust(tgt_expr, rest);
|
||||
}
|
||||
@ -1169,15 +1155,15 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
}
|
||||
self.walk_expr(*expr);
|
||||
if let Some(discr_place) = self.place_of_expr(*expr) {
|
||||
if self.is_upvar(&discr_place) {
|
||||
let mut capture_mode = None;
|
||||
for arm in arms.iter() {
|
||||
self.walk_pat(&mut capture_mode, arm.pat);
|
||||
}
|
||||
if let Some(c) = capture_mode {
|
||||
self.push_capture(discr_place, c);
|
||||
}
|
||||
if let Some(discr_place) = self.place_of_expr(*expr)
|
||||
&& self.is_upvar(&discr_place)
|
||||
{
|
||||
let mut capture_mode = None;
|
||||
for arm in arms.iter() {
|
||||
self.walk_pat(&mut capture_mode, arm.pat);
|
||||
}
|
||||
if let Some(c) = capture_mode {
|
||||
self.push_capture(discr_place, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1209,13 +1195,11 @@ impl InferenceContext<'_> {
|
||||
let mutability = 'b: {
|
||||
if let Some(deref_trait) =
|
||||
self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait())
|
||||
{
|
||||
if let Some(deref_fn) = deref_trait
|
||||
&& let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
}
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
}
|
||||
false
|
||||
};
|
||||
@ -1405,10 +1389,10 @@ impl InferenceContext<'_> {
|
||||
|
||||
fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
|
||||
let mut ty = None;
|
||||
if let Some(it) = self.result.expr_adjustments.get(&e) {
|
||||
if let Some(it) = it.last() {
|
||||
ty = Some(it.target.clone());
|
||||
}
|
||||
if let Some(it) = self.result.expr_adjustments.get(&e)
|
||||
&& let Some(it) = it.last()
|
||||
{
|
||||
ty = Some(it.target.clone());
|
||||
}
|
||||
ty.unwrap_or_else(|| self.expr_ty(e))
|
||||
}
|
||||
@ -1793,10 +1777,10 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
|
||||
pub(super) fn add_current_closure_dependency(&mut self, dep: ClosureId) {
|
||||
if let Some(c) = self.current_closure {
|
||||
if !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep) {
|
||||
self.closure_dependencies.entry(c).or_default().push(dep);
|
||||
}
|
||||
if let Some(c) = self.current_closure
|
||||
&& !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep)
|
||||
{
|
||||
self.closure_dependencies.entry(c).or_default().push(dep);
|
||||
}
|
||||
|
||||
fn dep_creates_cycle(
|
||||
|
@ -164,14 +164,14 @@ impl CoerceMany {
|
||||
// - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
|
||||
// First try to coerce the new expression to the type of the previous ones,
|
||||
// but only if the new expression has no coercion already applied to it.
|
||||
if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) {
|
||||
if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
|
||||
self.final_ty = Some(res);
|
||||
if let Some(expr) = expr {
|
||||
self.expressions.push(expr);
|
||||
}
|
||||
return;
|
||||
if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr))
|
||||
&& let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes)
|
||||
{
|
||||
self.final_ty = Some(res);
|
||||
if let Some(expr) = expr {
|
||||
self.expressions.push(expr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok((adjustments, res)) =
|
||||
@ -322,18 +322,13 @@ impl InferenceTable<'_> {
|
||||
// If we are coercing into a TAIT, coerce into its proxy inference var, instead.
|
||||
let mut to_ty = to_ty;
|
||||
let _to;
|
||||
if let Some(tait_table) = &self.tait_coercion_table {
|
||||
if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) {
|
||||
if !matches!(
|
||||
from_ty.kind(Interner),
|
||||
TyKind::InferenceVar(..) | TyKind::OpaqueType(..)
|
||||
) {
|
||||
if let Some(ty) = tait_table.get(opaque_ty_id) {
|
||||
_to = ty.clone();
|
||||
to_ty = &_to;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(tait_table) = &self.tait_coercion_table
|
||||
&& let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner)
|
||||
&& !matches!(from_ty.kind(Interner), TyKind::InferenceVar(..) | TyKind::OpaqueType(..))
|
||||
&& let Some(ty) = tait_table.get(opaque_ty_id)
|
||||
{
|
||||
_to = ty.clone();
|
||||
to_ty = &_to;
|
||||
}
|
||||
|
||||
// Consider coercing the subtype to a DST
|
||||
@ -594,14 +589,13 @@ impl InferenceTable<'_> {
|
||||
F: FnOnce(Ty) -> Vec<Adjustment>,
|
||||
G: FnOnce(Ty) -> Vec<Adjustment>,
|
||||
{
|
||||
if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner) {
|
||||
if let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) =
|
||||
if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner)
|
||||
&& let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) =
|
||||
(from_fn_ptr.sig.safety, to_fn_ptr.sig.safety)
|
||||
{
|
||||
let from_unsafe =
|
||||
TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner);
|
||||
return self.unify_and(&from_unsafe, to_ty, to_unsafe);
|
||||
}
|
||||
{
|
||||
let from_unsafe =
|
||||
TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner);
|
||||
return self.unify_and(&from_unsafe, to_ty, to_unsafe);
|
||||
}
|
||||
self.unify_and(&from_ty, to_ty, normal)
|
||||
}
|
||||
|
@ -653,19 +653,18 @@ impl InferenceContext<'_> {
|
||||
// FIXME: Note down method resolution her
|
||||
match op {
|
||||
UnaryOp::Deref => {
|
||||
if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
|
||||
if let Some(deref_fn) = deref_trait
|
||||
if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref)
|
||||
&& let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref))
|
||||
{
|
||||
// FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
|
||||
// the mutability is not wrong, and will be fixed in `self.infer_mut`).
|
||||
self.write_method_resolution(
|
||||
tgt_expr,
|
||||
deref_fn,
|
||||
Substitution::empty(Interner),
|
||||
);
|
||||
}
|
||||
{
|
||||
// FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
|
||||
// the mutability is not wrong, and will be fixed in `self.infer_mut`).
|
||||
self.write_method_resolution(
|
||||
tgt_expr,
|
||||
deref_fn,
|
||||
Substitution::empty(Interner),
|
||||
);
|
||||
}
|
||||
if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
|
||||
self.resolve_ty_shallow(derefed)
|
||||
@ -1387,28 +1386,28 @@ impl InferenceContext<'_> {
|
||||
let ret_ty = match method_ty.callable_sig(self.db) {
|
||||
Some(sig) => {
|
||||
let p_left = &sig.params()[0];
|
||||
if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) {
|
||||
if let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner) {
|
||||
self.write_expr_adj(
|
||||
lhs,
|
||||
Box::new([Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
|
||||
target: p_left.clone(),
|
||||
}]),
|
||||
);
|
||||
}
|
||||
if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. })
|
||||
&& let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner)
|
||||
{
|
||||
self.write_expr_adj(
|
||||
lhs,
|
||||
Box::new([Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
|
||||
target: p_left.clone(),
|
||||
}]),
|
||||
);
|
||||
}
|
||||
let p_right = &sig.params()[1];
|
||||
if matches!(op, BinaryOp::CmpOp(..)) {
|
||||
if let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner) {
|
||||
self.write_expr_adj(
|
||||
rhs,
|
||||
Box::new([Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
|
||||
target: p_right.clone(),
|
||||
}]),
|
||||
);
|
||||
}
|
||||
if matches!(op, BinaryOp::CmpOp(..))
|
||||
&& let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner)
|
||||
{
|
||||
self.write_expr_adj(
|
||||
rhs,
|
||||
Box::new([Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
|
||||
target: p_right.clone(),
|
||||
}]),
|
||||
);
|
||||
}
|
||||
sig.ret().clone()
|
||||
}
|
||||
@ -1664,14 +1663,12 @@ impl InferenceContext<'_> {
|
||||
Some((ty, field_id, adjustments, is_public)) => {
|
||||
self.write_expr_adj(receiver, adjustments.into_boxed_slice());
|
||||
self.result.field_resolutions.insert(tgt_expr, field_id);
|
||||
if !is_public {
|
||||
if let Either::Left(field) = field_id {
|
||||
// FIXME: Merge this diagnostic into UnresolvedField?
|
||||
self.push_diagnostic(InferenceDiagnostic::PrivateField {
|
||||
expr: tgt_expr,
|
||||
field,
|
||||
});
|
||||
}
|
||||
if !is_public && let Either::Left(field) = field_id {
|
||||
// FIXME: Merge this diagnostic into UnresolvedField?
|
||||
self.push_diagnostic(InferenceDiagnostic::PrivateField {
|
||||
expr: tgt_expr,
|
||||
field,
|
||||
});
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
@ -124,53 +124,41 @@ impl InferenceContext<'_> {
|
||||
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
|
||||
}
|
||||
&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) =
|
||||
LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate)
|
||||
{
|
||||
if let Some(index_fn) = index_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::index_mut))
|
||||
{
|
||||
*f = index_fn;
|
||||
let mut base_ty = None;
|
||||
let base_adjustments = self
|
||||
.result
|
||||
.expr_adjustments
|
||||
.get_mut(&base)
|
||||
.and_then(|it| it.last_mut());
|
||||
if let Some(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
|
||||
target,
|
||||
}) = base_adjustments
|
||||
{
|
||||
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
|
||||
base_ty = Some(ty.clone());
|
||||
}
|
||||
*mutability = Mutability::Mut;
|
||||
}
|
||||
|
||||
// Apply `IndexMut` obligation for non-assignee expr
|
||||
if let Some(base_ty) = base_ty {
|
||||
let index_ty =
|
||||
if let Some(ty) = self.result.type_of_expr.get(index) {
|
||||
ty.clone()
|
||||
} else {
|
||||
self.infer_expr(
|
||||
index,
|
||||
&Expectation::none(),
|
||||
ExprIsRead::Yes,
|
||||
)
|
||||
};
|
||||
let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
|
||||
.push(base_ty)
|
||||
.fill(|_| index_ty.clone().cast(Interner))
|
||||
.build();
|
||||
self.push_obligation(trait_ref.cast(Interner));
|
||||
}
|
||||
}
|
||||
if mutability == Mutability::Mut
|
||||
&& let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr)
|
||||
&& let Some(index_trait) =
|
||||
LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate)
|
||||
&& let Some(index_fn) = index_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::index_mut))
|
||||
{
|
||||
*f = index_fn;
|
||||
let mut base_ty = None;
|
||||
let base_adjustments =
|
||||
self.result.expr_adjustments.get_mut(&base).and_then(|it| it.last_mut());
|
||||
if let Some(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
|
||||
target,
|
||||
}) = base_adjustments
|
||||
{
|
||||
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
|
||||
base_ty = Some(ty.clone());
|
||||
}
|
||||
*mutability = Mutability::Mut;
|
||||
}
|
||||
|
||||
// Apply `IndexMut` obligation for non-assignee expr
|
||||
if let Some(base_ty) = base_ty {
|
||||
let index_ty = if let Some(ty) = self.result.type_of_expr.get(index) {
|
||||
ty.clone()
|
||||
} else {
|
||||
self.infer_expr(index, &Expectation::none(), ExprIsRead::Yes)
|
||||
};
|
||||
let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
|
||||
.push(base_ty)
|
||||
.fill(|_| index_ty.clone().cast(Interner))
|
||||
.build();
|
||||
self.push_obligation(trait_ref.cast(Interner));
|
||||
}
|
||||
}
|
||||
self.infer_mut_expr(base, mutability);
|
||||
@ -178,28 +166,23 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
|
||||
let mut mutability = mutability;
|
||||
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
|
||||
if mutability == Mutability::Mut {
|
||||
if let Some(deref_trait) =
|
||||
LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate)
|
||||
{
|
||||
let ty = self.result.type_of_expr.get(*expr);
|
||||
let is_mut_ptr = ty.is_some_and(|ty| {
|
||||
let ty = self.table.resolve_ty_shallow(ty);
|
||||
matches!(
|
||||
ty.kind(Interner),
|
||||
chalk_ir::TyKind::Raw(Mutability::Mut, _)
|
||||
)
|
||||
});
|
||||
if is_mut_ptr {
|
||||
mutability = Mutability::Not;
|
||||
} else if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
*f = deref_fn;
|
||||
}
|
||||
}
|
||||
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr)
|
||||
&& mutability == Mutability::Mut
|
||||
&& let Some(deref_trait) =
|
||||
LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate)
|
||||
{
|
||||
let ty = self.result.type_of_expr.get(*expr);
|
||||
let is_mut_ptr = ty.is_some_and(|ty| {
|
||||
let ty = self.table.resolve_ty_shallow(ty);
|
||||
matches!(ty.kind(Interner), chalk_ir::TyKind::Raw(Mutability::Mut, _))
|
||||
});
|
||||
if is_mut_ptr {
|
||||
mutability = Mutability::Not;
|
||||
} else if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
*f = deref_fn;
|
||||
}
|
||||
}
|
||||
self.infer_mut_expr(*expr, mutability);
|
||||
|
@ -498,12 +498,12 @@ impl InferenceContext<'_> {
|
||||
|
||||
// If `expected` is an infer ty, we try to equate it to an array if the given pattern
|
||||
// allows it. See issue #16609
|
||||
if self.pat_is_irrefutable(decl) && expected.is_ty_var() {
|
||||
if let Some(resolved_array_ty) =
|
||||
if self.pat_is_irrefutable(decl)
|
||||
&& expected.is_ty_var()
|
||||
&& let Some(resolved_array_ty) =
|
||||
self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice)
|
||||
{
|
||||
self.unify(&expected, &resolved_array_ty);
|
||||
}
|
||||
{
|
||||
self.unify(&expected, &resolved_array_ty);
|
||||
}
|
||||
|
||||
let expected = self.resolve_ty_shallow(&expected);
|
||||
@ -539,17 +539,16 @@ impl InferenceContext<'_> {
|
||||
|
||||
fn infer_lit_pat(&mut self, expr: ExprId, expected: &Ty) -> Ty {
|
||||
// Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`.
|
||||
if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] {
|
||||
if let Some((inner, ..)) = expected.as_reference() {
|
||||
let inner = self.resolve_ty_shallow(inner);
|
||||
if matches!(inner.kind(Interner), TyKind::Slice(_)) {
|
||||
let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
|
||||
let slice_ty = TyKind::Slice(elem_ty).intern(Interner);
|
||||
let ty =
|
||||
TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner);
|
||||
self.write_expr_ty(expr, ty.clone());
|
||||
return ty;
|
||||
}
|
||||
if let Expr::Literal(Literal::ByteString(_)) = self.body[expr]
|
||||
&& let Some((inner, ..)) = expected.as_reference()
|
||||
{
|
||||
let inner = self.resolve_ty_shallow(inner);
|
||||
if matches!(inner.kind(Interner), TyKind::Slice(_)) {
|
||||
let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
|
||||
let slice_ty = TyKind::Slice(elem_ty).intern(Interner);
|
||||
let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner);
|
||||
self.write_expr_ty(expr, ty.clone());
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -830,10 +830,10 @@ fn named_associated_type_shorthand_candidates<R>(
|
||||
let data = t.hir_trait_id().trait_items(db);
|
||||
|
||||
for (name, assoc_id) in &data.items {
|
||||
if let AssocItemId::TypeAliasId(alias) = assoc_id {
|
||||
if let Some(result) = cb(name, &t, *alias) {
|
||||
return Some(result);
|
||||
}
|
||||
if let AssocItemId::TypeAliasId(alias) = assoc_id
|
||||
&& let Some(result) = cb(name, &t, *alias)
|
||||
{
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -360,15 +360,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(enum_segment) = enum_segment {
|
||||
if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
{
|
||||
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
|
||||
segment: (enum_segment + 1) as u32,
|
||||
reason: GenericArgsProhibitedReason::EnumVariant,
|
||||
});
|
||||
}
|
||||
if let Some(enum_segment) = enum_segment
|
||||
&& segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
{
|
||||
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
|
||||
segment: (enum_segment + 1) as u32,
|
||||
reason: GenericArgsProhibitedReason::EnumVariant,
|
||||
});
|
||||
}
|
||||
|
||||
self.handle_type_ns_resolution(&resolution);
|
||||
@ -417,15 +416,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(enum_segment) = enum_segment {
|
||||
if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
{
|
||||
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
|
||||
segment: (enum_segment + 1) as u32,
|
||||
reason: GenericArgsProhibitedReason::EnumVariant,
|
||||
});
|
||||
}
|
||||
if let Some(enum_segment) = enum_segment
|
||||
&& segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
|
||||
{
|
||||
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
|
||||
segment: (enum_segment + 1) as u32,
|
||||
reason: GenericArgsProhibitedReason::EnumVariant,
|
||||
});
|
||||
}
|
||||
|
||||
match &res {
|
||||
@ -576,13 +574,12 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
// This simplifies the code a bit.
|
||||
let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
|
||||
let penultimate = self.segments.get(penultimate_idx);
|
||||
if let Some(penultimate) = penultimate {
|
||||
if self.current_or_prev_segment.args_and_bindings.is_none()
|
||||
&& penultimate.args_and_bindings.is_some()
|
||||
{
|
||||
self.current_segment_idx = penultimate_idx;
|
||||
self.current_or_prev_segment = penultimate;
|
||||
}
|
||||
if let Some(penultimate) = penultimate
|
||||
&& self.current_or_prev_segment.args_and_bindings.is_none()
|
||||
&& penultimate.args_and_bindings.is_some()
|
||||
{
|
||||
self.current_segment_idx = penultimate_idx;
|
||||
self.current_or_prev_segment = penultimate;
|
||||
}
|
||||
var.lookup(self.ctx.db).parent.into()
|
||||
}
|
||||
@ -607,37 +604,36 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
) -> Substitution {
|
||||
let mut lifetime_elision = self.ctx.lifetime_elision.clone();
|
||||
|
||||
if let Some(args) = self.current_or_prev_segment.args_and_bindings {
|
||||
if args.parenthesized != GenericArgsParentheses::No {
|
||||
let prohibit_parens = match def {
|
||||
GenericDefId::TraitId(trait_) => {
|
||||
// RTN is prohibited anyways if we got here.
|
||||
let is_rtn =
|
||||
args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
|
||||
let is_fn_trait = self
|
||||
.ctx
|
||||
.db
|
||||
.trait_signature(trait_)
|
||||
.flags
|
||||
.contains(TraitFlags::RUSTC_PAREN_SUGAR);
|
||||
is_rtn || !is_fn_trait
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if prohibit_parens {
|
||||
let segment = self.current_segment_u32();
|
||||
self.on_diagnostic(
|
||||
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
|
||||
);
|
||||
|
||||
return TyBuilder::unknown_subst(self.ctx.db, def);
|
||||
if let Some(args) = self.current_or_prev_segment.args_and_bindings
|
||||
&& args.parenthesized != GenericArgsParentheses::No
|
||||
{
|
||||
let prohibit_parens = match def {
|
||||
GenericDefId::TraitId(trait_) => {
|
||||
// RTN is prohibited anyways if we got here.
|
||||
let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
|
||||
let is_fn_trait = self
|
||||
.ctx
|
||||
.db
|
||||
.trait_signature(trait_)
|
||||
.flags
|
||||
.contains(TraitFlags::RUSTC_PAREN_SUGAR);
|
||||
is_rtn || !is_fn_trait
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
|
||||
lifetime_elision =
|
||||
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
|
||||
if prohibit_parens {
|
||||
let segment = self.current_segment_u32();
|
||||
self.on_diagnostic(
|
||||
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
|
||||
);
|
||||
|
||||
return TyBuilder::unknown_subst(self.ctx.db, def);
|
||||
}
|
||||
|
||||
// `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
|
||||
lifetime_elision =
|
||||
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
|
||||
}
|
||||
|
||||
self.substs_from_args_and_bindings(
|
||||
@ -753,18 +749,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
match param {
|
||||
GenericParamDataRef::LifetimeParamData(_) => error_lifetime().cast(Interner),
|
||||
GenericParamDataRef::TypeParamData(param) => {
|
||||
if !infer_args && param.default.is_some() {
|
||||
if let Some(default) = default() {
|
||||
return default;
|
||||
}
|
||||
if !infer_args
|
||||
&& param.default.is_some()
|
||||
&& let Some(default) = default()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
TyKind::Error.intern(Interner).cast(Interner)
|
||||
}
|
||||
GenericParamDataRef::ConstParamData(param) => {
|
||||
if !infer_args && param.default.is_some() {
|
||||
if let Some(default) = default() {
|
||||
return default;
|
||||
}
|
||||
if !infer_args
|
||||
&& param.default.is_some()
|
||||
&& let Some(default) = default()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
let GenericParamId::ConstParamId(const_id) = param_id else {
|
||||
unreachable!("non-const param ID for const param");
|
||||
|
@ -581,15 +581,15 @@ impl ReceiverAdjustments {
|
||||
}
|
||||
if self.unsize_array {
|
||||
ty = 'it: {
|
||||
if let TyKind::Ref(m, l, inner) = ty.kind(Interner) {
|
||||
if let TyKind::Array(inner, _) = inner.kind(Interner) {
|
||||
break 'it TyKind::Ref(
|
||||
*m,
|
||||
l.clone(),
|
||||
TyKind::Slice(inner.clone()).intern(Interner),
|
||||
)
|
||||
.intern(Interner);
|
||||
}
|
||||
if let TyKind::Ref(m, l, inner) = ty.kind(Interner)
|
||||
&& let TyKind::Array(inner, _) = inner.kind(Interner)
|
||||
{
|
||||
break 'it TyKind::Ref(
|
||||
*m,
|
||||
l.clone(),
|
||||
TyKind::Slice(inner.clone()).intern(Interner),
|
||||
)
|
||||
.intern(Interner);
|
||||
}
|
||||
// FIXME: report diagnostic if array unsizing happens without indirection.
|
||||
ty
|
||||
@ -1549,11 +1549,11 @@ fn is_valid_impl_method_candidate(
|
||||
check_that!(receiver_ty.is_none());
|
||||
check_that!(name.is_none_or(|n| n == item_name));
|
||||
|
||||
if let Some(from_module) = visible_from_module {
|
||||
if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) {
|
||||
cov_mark::hit!(const_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
if let Some(from_module) = visible_from_module
|
||||
&& !db.assoc_visibility(c.into()).is_visible_from(db, from_module)
|
||||
{
|
||||
cov_mark::hit!(const_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
let self_ty_matches = table.run_in_snapshot(|table| {
|
||||
let expected_self_ty =
|
||||
@ -1638,11 +1638,11 @@ fn is_valid_impl_fn_candidate(
|
||||
let db = table.db;
|
||||
let data = db.function_signature(fn_id);
|
||||
|
||||
if let Some(from_module) = visible_from_module {
|
||||
if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) {
|
||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
if let Some(from_module) = visible_from_module
|
||||
&& !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module)
|
||||
{
|
||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
table.run_in_snapshot(|table| {
|
||||
let _p = tracing::info_span!("subst_for_def").entered();
|
||||
|
@ -559,10 +559,9 @@ fn mutability_of_locals(
|
||||
},
|
||||
p,
|
||||
) = value
|
||||
&& place_case(db, body, p) != ProjectionCase::Indirect
|
||||
{
|
||||
if place_case(db, body, p) != ProjectionCase::Indirect {
|
||||
push_mut_span(p.local, statement.span, &mut result);
|
||||
}
|
||||
push_mut_span(p.local, statement.span, &mut result);
|
||||
}
|
||||
}
|
||||
StatementKind::FakeRead(p) => {
|
||||
|
@ -1082,18 +1082,18 @@ impl Evaluator<'_> {
|
||||
let stack_size = {
|
||||
let mut stack_ptr = self.stack.len();
|
||||
for (id, it) in body.locals.iter() {
|
||||
if id == return_slot() {
|
||||
if let Some(destination) = destination {
|
||||
locals.ptr.insert(id, destination);
|
||||
continue;
|
||||
}
|
||||
if id == return_slot()
|
||||
&& let Some(destination) = destination
|
||||
{
|
||||
locals.ptr.insert(id, destination);
|
||||
continue;
|
||||
}
|
||||
let (size, align) = self.size_align_of_sized(
|
||||
&it.ty,
|
||||
&locals,
|
||||
"no unsized local in extending stack",
|
||||
)?;
|
||||
while stack_ptr % align != 0 {
|
||||
while !stack_ptr.is_multiple_of(align) {
|
||||
stack_ptr += 1;
|
||||
}
|
||||
let my_ptr = stack_ptr;
|
||||
@ -1673,14 +1673,14 @@ impl Evaluator<'_> {
|
||||
if let Some(it) = goal(kind) {
|
||||
return Ok(it);
|
||||
}
|
||||
if let TyKind::Adt(id, subst) = kind {
|
||||
if let AdtId::StructId(struct_id) = id.0 {
|
||||
let field_types = self.db.field_types(struct_id.into());
|
||||
if let Some(ty) =
|
||||
field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst))
|
||||
{
|
||||
return self.coerce_unsized_look_through_fields(&ty, goal);
|
||||
}
|
||||
if let TyKind::Adt(id, subst) = kind
|
||||
&& let AdtId::StructId(struct_id) = id.0
|
||||
{
|
||||
let field_types = self.db.field_types(struct_id.into());
|
||||
if let Some(ty) =
|
||||
field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst))
|
||||
{
|
||||
return self.coerce_unsized_look_through_fields(&ty, goal);
|
||||
}
|
||||
}
|
||||
Err(MirEvalError::CoerceUnsizedError(ty.clone()))
|
||||
@ -1778,17 +1778,15 @@ impl Evaluator<'_> {
|
||||
locals: &Locals,
|
||||
) -> Result<(usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
|
||||
let adt = it.adt_id(self.db);
|
||||
if let DefWithBodyId::VariantId(f) = locals.body.owner {
|
||||
if let VariantId::EnumVariantId(it) = it {
|
||||
if let AdtId::EnumId(e) = adt {
|
||||
if f.lookup(self.db).parent == e {
|
||||
// Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
|
||||
// infinite sized type errors) we use a dummy layout
|
||||
let i = self.const_eval_discriminant(it)?;
|
||||
return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let DefWithBodyId::VariantId(f) = locals.body.owner
|
||||
&& let VariantId::EnumVariantId(it) = it
|
||||
&& let AdtId::EnumId(e) = adt
|
||||
&& f.lookup(self.db).parent == e
|
||||
{
|
||||
// Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
|
||||
// infinite sized type errors) we use a dummy layout
|
||||
let i = self.const_eval_discriminant(it)?;
|
||||
return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i))));
|
||||
}
|
||||
let layout = self.layout_adt(adt, subst)?;
|
||||
Ok(match &layout.variants {
|
||||
@ -1909,10 +1907,10 @@ impl Evaluator<'_> {
|
||||
let name = const_id.name(self.db);
|
||||
MirEvalError::ConstEvalError(name, Box::new(e))
|
||||
})?;
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
|
||||
if let ConstScalar::Bytes(v, mm) = &c.interned {
|
||||
break 'b (v, mm);
|
||||
}
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value
|
||||
&& let ConstScalar::Bytes(v, mm) = &c.interned
|
||||
{
|
||||
break 'b (v, mm);
|
||||
}
|
||||
not_supported!("unevaluatable constant");
|
||||
}
|
||||
@ -2055,14 +2053,13 @@ impl Evaluator<'_> {
|
||||
.is_sized()
|
||||
.then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize)));
|
||||
}
|
||||
if let DefWithBodyId::VariantId(f) = locals.body.owner {
|
||||
if let Some((AdtId::EnumId(e), _)) = ty.as_adt() {
|
||||
if f.lookup(self.db).parent == e {
|
||||
// Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
|
||||
// infinite sized type errors) we use a dummy size
|
||||
return Ok(Some((16, 16)));
|
||||
}
|
||||
}
|
||||
if let DefWithBodyId::VariantId(f) = locals.body.owner
|
||||
&& let Some((AdtId::EnumId(e), _)) = ty.as_adt()
|
||||
&& f.lookup(self.db).parent == e
|
||||
{
|
||||
// Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
|
||||
// infinite sized type errors) we use a dummy size
|
||||
return Ok(Some((16, 16)));
|
||||
}
|
||||
let layout = self.layout(ty);
|
||||
if self.assert_placeholder_ty_is_unused
|
||||
@ -2103,7 +2100,7 @@ impl Evaluator<'_> {
|
||||
if !align.is_power_of_two() || align > 10000 {
|
||||
return Err(MirEvalError::UndefinedBehavior(format!("Alignment {align} is invalid")));
|
||||
}
|
||||
while self.heap.len() % align != 0 {
|
||||
while !self.heap.len().is_multiple_of(align) {
|
||||
self.heap.push(0);
|
||||
}
|
||||
if size.checked_add(self.heap.len()).is_none_or(|x| x > self.memory_limit) {
|
||||
|
@ -119,25 +119,25 @@ impl Evaluator<'_> {
|
||||
destination.write_from_bytes(self, &result)?;
|
||||
return Ok(true);
|
||||
}
|
||||
if let ItemContainerId::TraitId(t) = def.lookup(self.db).container {
|
||||
if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
|
||||
let [self_ty] = generic_args.as_slice(Interner) else {
|
||||
not_supported!("wrong generic arg count for clone");
|
||||
};
|
||||
let Some(self_ty) = self_ty.ty(Interner) else {
|
||||
not_supported!("wrong generic arg kind for clone");
|
||||
};
|
||||
// Clone has special impls for tuples and function pointers
|
||||
if matches!(
|
||||
self_ty.kind(Interner),
|
||||
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
|
||||
) {
|
||||
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||
return Ok(true);
|
||||
}
|
||||
// Return early to prevent caching clone as non special fn.
|
||||
return Ok(false);
|
||||
if let ItemContainerId::TraitId(t) = def.lookup(self.db).container
|
||||
&& self.db.lang_attr(t.into()) == Some(LangItem::Clone)
|
||||
{
|
||||
let [self_ty] = generic_args.as_slice(Interner) else {
|
||||
not_supported!("wrong generic arg count for clone");
|
||||
};
|
||||
let Some(self_ty) = self_ty.ty(Interner) else {
|
||||
not_supported!("wrong generic arg kind for clone");
|
||||
};
|
||||
// Clone has special impls for tuples and function pointers
|
||||
if matches!(
|
||||
self_ty.kind(Interner),
|
||||
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
|
||||
) {
|
||||
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||
return Ok(true);
|
||||
}
|
||||
// Return early to prevent caching clone as non special fn.
|
||||
return Ok(false);
|
||||
}
|
||||
self.not_special_fn_cache.borrow_mut().insert(def);
|
||||
Ok(false)
|
||||
@ -1256,23 +1256,22 @@ impl Evaluator<'_> {
|
||||
let addr = tuple.interval.addr.offset(offset);
|
||||
args.push(IntervalAndTy::new(addr, field, self, locals)?);
|
||||
}
|
||||
if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) {
|
||||
if let Some(def) = target
|
||||
if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id)
|
||||
&& let Some(def) = target
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::call_once))
|
||||
{
|
||||
self.exec_fn_trait(
|
||||
def,
|
||||
&args,
|
||||
// FIXME: wrong for manual impls of `FnOnce`
|
||||
Substitution::empty(Interner),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
span,
|
||||
)?;
|
||||
return Ok(true);
|
||||
}
|
||||
{
|
||||
self.exec_fn_trait(
|
||||
def,
|
||||
&args,
|
||||
// FIXME: wrong for manual impls of `FnOnce`
|
||||
Substitution::empty(Interner),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
span,
|
||||
)?;
|
||||
return Ok(true);
|
||||
}
|
||||
not_supported!("FnOnce was not available for executing const_eval_select");
|
||||
}
|
||||
@ -1367,12 +1366,11 @@ impl Evaluator<'_> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if signed {
|
||||
if let Some((&l, &r)) = lhs.iter().zip(rhs).next_back() {
|
||||
if l != r {
|
||||
result = (l as i8).cmp(&(r as i8));
|
||||
}
|
||||
}
|
||||
if signed
|
||||
&& let Some((&l, &r)) = lhs.iter().zip(rhs).next_back()
|
||||
&& l != r
|
||||
{
|
||||
result = (l as i8).cmp(&(r as i8));
|
||||
}
|
||||
if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) {
|
||||
let ty = self.db.ty(e.into());
|
||||
|
@ -114,12 +114,11 @@ impl Evaluator<'_> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if is_signed {
|
||||
if let Some((&l, &r)) = l.iter().zip(r).next_back() {
|
||||
if l != r {
|
||||
result = (l as i8).cmp(&(r as i8));
|
||||
}
|
||||
}
|
||||
if is_signed
|
||||
&& let Some((&l, &r)) = l.iter().zip(r).next_back()
|
||||
&& l != r
|
||||
{
|
||||
result = (l as i8).cmp(&(r as i8));
|
||||
}
|
||||
let result = match result {
|
||||
Ordering::Less => ["lt", "le", "ne"].contains(&name),
|
||||
|
@ -320,11 +320,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
expr_id: ExprId,
|
||||
current: BasicBlockId,
|
||||
) -> Result<Option<(Operand, BasicBlockId)>> {
|
||||
if !self.has_adjustments(expr_id) {
|
||||
if let Expr::Literal(l) = &self.body[expr_id] {
|
||||
let ty = self.expr_ty_without_adjust(expr_id);
|
||||
return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));
|
||||
}
|
||||
if !self.has_adjustments(expr_id)
|
||||
&& let Expr::Literal(l) = &self.body[expr_id]
|
||||
{
|
||||
let ty = self.expr_ty_without_adjust(expr_id);
|
||||
return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));
|
||||
}
|
||||
let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else {
|
||||
return Ok(None);
|
||||
@ -1039,18 +1039,18 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
&& rhs_ty.is_scalar()
|
||||
&& (lhs_ty == rhs_ty || builtin_inequal_impls)
|
||||
};
|
||||
if !is_builtin {
|
||||
if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
|
||||
let func = Operand::from_fn(self.db, func_id, generic_args);
|
||||
return self.lower_call_and_args(
|
||||
func,
|
||||
[*lhs, *rhs].into_iter(),
|
||||
place,
|
||||
current,
|
||||
self.is_uninhabited(expr_id),
|
||||
expr_id.into(),
|
||||
);
|
||||
}
|
||||
if !is_builtin
|
||||
&& let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id)
|
||||
{
|
||||
let func = Operand::from_fn(self.db, func_id, generic_args);
|
||||
return self.lower_call_and_args(
|
||||
func,
|
||||
[*lhs, *rhs].into_iter(),
|
||||
place,
|
||||
current,
|
||||
self.is_uninhabited(expr_id),
|
||||
expr_id.into(),
|
||||
);
|
||||
}
|
||||
if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {
|
||||
// last adjustment is `&mut` which we don't want it.
|
||||
@ -1596,10 +1596,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
|
||||
fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
|
||||
let mut ty = None;
|
||||
if let Some(it) = self.infer.expr_adjustments.get(&e) {
|
||||
if let Some(it) = it.last() {
|
||||
ty = Some(it.target.clone());
|
||||
}
|
||||
if let Some(it) = self.infer.expr_adjustments.get(&e)
|
||||
&& let Some(it) = it.last()
|
||||
{
|
||||
ty = Some(it.target.clone());
|
||||
}
|
||||
ty.unwrap_or_else(|| self.expr_ty_without_adjust(e))
|
||||
}
|
||||
@ -1848,13 +1848,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
self.result.param_locals.extend(params.clone().map(|(it, ty)| {
|
||||
let local_id = self.result.locals.alloc(Local { ty });
|
||||
self.drop_scopes.last_mut().unwrap().locals.push(local_id);
|
||||
if let Pat::Bind { id, subpat: None } = self.body[it] {
|
||||
if matches!(
|
||||
if let Pat::Bind { id, subpat: None } = self.body[it]
|
||||
&& matches!(
|
||||
self.body[id].mode,
|
||||
BindingAnnotation::Unannotated | BindingAnnotation::Mutable
|
||||
) {
|
||||
self.result.binding_locals.insert(id, local_id);
|
||||
}
|
||||
)
|
||||
{
|
||||
self.result.binding_locals.insert(id, local_id);
|
||||
}
|
||||
local_id
|
||||
}));
|
||||
@ -1887,10 +1887,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
.into_iter()
|
||||
.skip(base_param_count + self_binding.is_some() as usize);
|
||||
for ((param, _), local) in params.zip(local_params) {
|
||||
if let Pat::Bind { id, .. } = self.body[param] {
|
||||
if local == self.binding_local(id)? {
|
||||
continue;
|
||||
}
|
||||
if let Pat::Bind { id, .. } = self.body[param]
|
||||
&& local == self.binding_local(id)?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let r = self.pattern_match(current, None, local.into(), param)?;
|
||||
if let Some(b) = r.1 {
|
||||
|
@ -189,17 +189,14 @@ impl MirLowerCtx<'_> {
|
||||
self.expr_ty_without_adjust(expr_id),
|
||||
expr_id.into(),
|
||||
'b: {
|
||||
if let Some((f, _)) = self.infer.method_resolution(expr_id) {
|
||||
if let Some(deref_trait) =
|
||||
if let Some((f, _)) = self.infer.method_resolution(expr_id)
|
||||
&& let Some(deref_trait) =
|
||||
self.resolve_lang_item(LangItem::DerefMut)?.as_trait()
|
||||
{
|
||||
if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
}
|
||||
}
|
||||
&& let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
}
|
||||
false
|
||||
},
|
||||
|
@ -317,27 +317,26 @@ impl MirLowerCtx<'_> {
|
||||
(current, current_else) =
|
||||
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
|
||||
}
|
||||
if let &Some(slice) = slice {
|
||||
if mode != MatchingMode::Check {
|
||||
if let Pat::Bind { id, subpat: _ } = self.body[slice] {
|
||||
let next_place = cond_place.project(
|
||||
ProjectionElem::Subslice {
|
||||
from: prefix.len() as u64,
|
||||
to: suffix.len() as u64,
|
||||
},
|
||||
&mut self.result.projection_store,
|
||||
);
|
||||
let mode = self.infer.binding_modes[slice];
|
||||
(current, current_else) = self.pattern_match_binding(
|
||||
id,
|
||||
mode,
|
||||
next_place,
|
||||
(slice).into(),
|
||||
current,
|
||||
current_else,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if let &Some(slice) = slice
|
||||
&& mode != MatchingMode::Check
|
||||
&& let Pat::Bind { id, subpat: _ } = self.body[slice]
|
||||
{
|
||||
let next_place = cond_place.project(
|
||||
ProjectionElem::Subslice {
|
||||
from: prefix.len() as u64,
|
||||
to: suffix.len() as u64,
|
||||
},
|
||||
&mut self.result.projection_store,
|
||||
);
|
||||
let mode = self.infer.binding_modes[slice];
|
||||
(current, current_else) = self.pattern_match_binding(
|
||||
id,
|
||||
mode,
|
||||
next_place,
|
||||
(slice).into(),
|
||||
current,
|
||||
current_else,
|
||||
)?;
|
||||
}
|
||||
for (i, &pat) in suffix.iter().enumerate() {
|
||||
let next_place = cond_place.project(
|
||||
@ -391,10 +390,10 @@ impl MirLowerCtx<'_> {
|
||||
return Ok((current, current_else));
|
||||
}
|
||||
let (c, subst) = 'b: {
|
||||
if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) {
|
||||
if let AssocItemId::ConstId(c) = x.0 {
|
||||
break 'b (c, x.1);
|
||||
}
|
||||
if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern)
|
||||
&& let AssocItemId::ConstId(c) = x.0
|
||||
{
|
||||
break 'b (c, x.1);
|
||||
}
|
||||
if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr {
|
||||
break 'b (c, Substitution::empty(Interner));
|
||||
|
@ -149,7 +149,7 @@ impl TestDB {
|
||||
.into_iter()
|
||||
.filter_map(|file_id| {
|
||||
let text = self.file_text(file_id.file_id(self));
|
||||
let annotations = extract_annotations(&text.text(self));
|
||||
let annotations = extract_annotations(text.text(self));
|
||||
if annotations.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
@ -125,11 +125,10 @@ pub(crate) fn trait_solve_query(
|
||||
alias: AliasTy::Projection(projection_ty),
|
||||
..
|
||||
}))) = &goal.value.goal.data(Interner)
|
||||
&& let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
|
||||
{
|
||||
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
|
||||
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
|
||||
return Some(Solution::Ambig(Guidance::Unknown));
|
||||
}
|
||||
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
|
||||
return Some(Solution::Ambig(Guidance::Unknown));
|
||||
}
|
||||
|
||||
// Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
|
||||
|
@ -333,13 +333,13 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
||||
constant: Const,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> Result<Const, Self::Error> {
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
|
||||
if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
return Ok(eval);
|
||||
} else {
|
||||
return Ok(unknown_const(constant.data(Interner).ty.clone()));
|
||||
}
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value
|
||||
&& let ConstScalar::UnevaluatedConst(id, subst) = &c.interned
|
||||
{
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
return Ok(eval);
|
||||
} else {
|
||||
return Ok(unknown_const(constant.data(Interner).ty.clone()));
|
||||
}
|
||||
}
|
||||
Ok(constant)
|
||||
|
@ -604,13 +604,13 @@ impl<'db> AnyDiagnostic<'db> {
|
||||
}
|
||||
}
|
||||
BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr } => {
|
||||
if let Ok(source_ptr) = source_map.expr_syntax(if_expr) {
|
||||
if let Some(ptr) = source_ptr.value.cast::<ast::IfExpr>() {
|
||||
return Some(
|
||||
RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) }
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
if let Ok(source_ptr) = source_map.expr_syntax(if_expr)
|
||||
&& let Some(ptr) = source_ptr.value.cast::<ast::IfExpr>()
|
||||
{
|
||||
return Some(
|
||||
RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) }
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1020,21 +1020,21 @@ fn emit_macro_def_diagnostics<'db>(
|
||||
m: Macro,
|
||||
) {
|
||||
let id = db.macro_def(m.id);
|
||||
if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
|
||||
if let Some(e) = expander.mac.err() {
|
||||
let Some(ast) = id.ast_id().left() else {
|
||||
never!("declarative expander for non decl-macro: {:?}", e);
|
||||
return;
|
||||
};
|
||||
let krate = HasModule::krate(&m.id, db);
|
||||
let edition = krate.data(db).edition;
|
||||
emit_def_diagnostic_(
|
||||
db,
|
||||
acc,
|
||||
&DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
|
||||
edition,
|
||||
);
|
||||
}
|
||||
if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id)
|
||||
&& let Some(e) = expander.mac.err()
|
||||
{
|
||||
let Some(ast) = id.ast_id().left() else {
|
||||
never!("declarative expander for non decl-macro: {:?}", e);
|
||||
return;
|
||||
};
|
||||
let krate = HasModule::krate(&m.id, db);
|
||||
let edition = krate.data(db).edition;
|
||||
emit_def_diagnostic_(
|
||||
db,
|
||||
acc,
|
||||
&DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
|
||||
edition,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2564,10 +2564,10 @@ impl<'db> Param<'db> {
|
||||
Callee::Closure(closure, _) => {
|
||||
let c = db.lookup_intern_closure(closure.into());
|
||||
let body = db.body(c.0);
|
||||
if let Expr::Closure { args, .. } = &body[c.1] {
|
||||
if let Pat::Bind { id, .. } = &body[args[self.idx]] {
|
||||
return Some(Local { parent: c.0, binding_id: *id });
|
||||
}
|
||||
if let Expr::Closure { args, .. } = &body[c.1]
|
||||
&& let Pat::Bind { id, .. } = &body[args[self.idx]]
|
||||
{
|
||||
return Some(Local { parent: c.0, binding_id: *id });
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -2761,26 +2761,20 @@ impl EvaluatedConst {
|
||||
|
||||
pub fn render_debug(&self, db: &dyn HirDatabase) -> Result<String, MirEvalError> {
|
||||
let data = self.const_.data(Interner);
|
||||
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
|
||||
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
|
||||
if let hir_ty::ConstValue::Concrete(c) = &data.value {
|
||||
if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned {
|
||||
let value = u128::from_le_bytes(mir::pad16(b, false));
|
||||
let value_signed =
|
||||
i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_))));
|
||||
let mut result = if let Scalar::Int(_) = s {
|
||||
value_signed.to_string()
|
||||
} else {
|
||||
value.to_string()
|
||||
};
|
||||
if value >= 10 {
|
||||
format_to!(result, " ({value:#X})");
|
||||
return Ok(result);
|
||||
} else {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let TyKind::Scalar(s) = data.ty.kind(Interner)
|
||||
&& matches!(s, Scalar::Int(_) | Scalar::Uint(_))
|
||||
&& let hir_ty::ConstValue::Concrete(c) = &data.value
|
||||
&& let hir_ty::ConstScalar::Bytes(b, _) = &c.interned
|
||||
{
|
||||
let value = u128::from_le_bytes(mir::pad16(b, false));
|
||||
let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_))));
|
||||
let mut result =
|
||||
if let Scalar::Int(_) = s { value_signed.to_string() } else { value.to_string() };
|
||||
if value >= 10 {
|
||||
format_to!(result, " ({value:#X})");
|
||||
return Ok(result);
|
||||
} else {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
mir::render_const_using_debug_impl(db, self.def, &self.const_)
|
||||
@ -4421,10 +4415,10 @@ impl Impl {
|
||||
let impls = db.trait_impls_in_crate(id);
|
||||
all.extend(impls.for_trait(trait_.id).map(Self::from))
|
||||
}
|
||||
if let Some(block) = module.id.containing_block() {
|
||||
if let Some(trait_impls) = db.trait_impls_in_block(block) {
|
||||
all.extend(trait_impls.for_trait(trait_.id).map(Self::from));
|
||||
}
|
||||
if let Some(block) = module.id.containing_block()
|
||||
&& let Some(trait_impls) = db.trait_impls_in_block(block)
|
||||
{
|
||||
all.extend(trait_impls.for_trait(trait_.id).map(Self::from));
|
||||
}
|
||||
all
|
||||
}
|
||||
|
@ -933,19 +933,18 @@ impl<'db> SemanticsImpl<'db> {
|
||||
InFile::new(file.file_id, last),
|
||||
false,
|
||||
&mut |InFile { value: last, file_id: last_fid }, _ctx| {
|
||||
if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
|
||||
if first_fid == last_fid {
|
||||
if let Some(p) = first.parent() {
|
||||
let range = first.text_range().cover(last.text_range());
|
||||
let node = find_root(&p)
|
||||
.covering_element(range)
|
||||
.ancestors()
|
||||
.take_while(|it| it.text_range() == range)
|
||||
.find_map(N::cast);
|
||||
if let Some(node) = node {
|
||||
res.push(node);
|
||||
}
|
||||
}
|
||||
if let Some(InFile { value: first, file_id: first_fid }) = scratch.next()
|
||||
&& first_fid == last_fid
|
||||
&& let Some(p) = first.parent()
|
||||
{
|
||||
let range = first.text_range().cover(last.text_range());
|
||||
let node = find_root(&p)
|
||||
.covering_element(range)
|
||||
.ancestors()
|
||||
.take_while(|it| it.text_range() == range)
|
||||
.find_map(N::cast);
|
||||
if let Some(node) = node {
|
||||
res.push(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1391,10 +1390,10 @@ impl<'db> SemanticsImpl<'db> {
|
||||
}
|
||||
})()
|
||||
.is_none();
|
||||
if was_not_remapped {
|
||||
if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) {
|
||||
return Some(b);
|
||||
}
|
||||
if was_not_remapped
|
||||
&& let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx)
|
||||
{
|
||||
return Some(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2068,14 +2067,12 @@ impl<'db> SemanticsImpl<'db> {
|
||||
break false;
|
||||
}
|
||||
|
||||
if let Some(parent) = ast::Expr::cast(parent.clone()) {
|
||||
if let Some(ExprOrPatId::ExprId(expr_id)) =
|
||||
if let Some(parent) = ast::Expr::cast(parent.clone())
|
||||
&& let Some(ExprOrPatId::ExprId(expr_id)) =
|
||||
source_map.node_expr(InFile { file_id, value: &parent })
|
||||
{
|
||||
if let Expr::Unsafe { .. } = body[expr_id] {
|
||||
break true;
|
||||
}
|
||||
}
|
||||
&& let Expr::Unsafe { .. } = body[expr_id]
|
||||
{
|
||||
break true;
|
||||
}
|
||||
|
||||
let Some(parent_) = parent.parent() else { break false };
|
||||
@ -2354,32 +2351,30 @@ struct RenameConflictsVisitor<'a> {
|
||||
|
||||
impl RenameConflictsVisitor<'_> {
|
||||
fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
|
||||
if let Path::BarePath(path) = path {
|
||||
if let Some(name) = path.as_ident() {
|
||||
if *name.symbol() == self.new_name {
|
||||
if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
|
||||
self.db,
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
self.to_be_renamed,
|
||||
) {
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
} else if *name.symbol() == self.old_name {
|
||||
if let Some(conflicting) =
|
||||
self.resolver.rename_will_conflict_with_another_variable(
|
||||
self.db,
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
&self.new_name,
|
||||
self.to_be_renamed,
|
||||
)
|
||||
{
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
if let Path::BarePath(path) = path
|
||||
&& let Some(name) = path.as_ident()
|
||||
{
|
||||
if *name.symbol() == self.new_name {
|
||||
if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
|
||||
self.db,
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
self.to_be_renamed,
|
||||
) {
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
} else if *name.symbol() == self.old_name
|
||||
&& let Some(conflicting) = self.resolver.rename_will_conflict_with_another_variable(
|
||||
self.db,
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
&self.new_name,
|
||||
self.to_be_renamed,
|
||||
)
|
||||
{
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -995,11 +995,11 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
|
||||
// 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, &store)
|
||||
.map(|it| (it, None));
|
||||
}
|
||||
if let Some(use_tree) = parent().and_then(ast::UseTree::cast)
|
||||
&& use_tree.coloncolon_token().is_some()
|
||||
{
|
||||
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store)
|
||||
.map(|it| (it, None));
|
||||
}
|
||||
|
||||
let meta_path = path
|
||||
@ -1035,24 +1035,19 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
// }
|
||||
// ```
|
||||
Some(it) if matches!(it, PathResolution::Def(ModuleDef::BuiltinType(_))) => {
|
||||
if let Some(mod_path) = hir_path.mod_path() {
|
||||
if let Some(ModuleDefId::ModuleId(id)) =
|
||||
if let Some(mod_path) = hir_path.mod_path()
|
||||
&& let Some(ModuleDefId::ModuleId(id)) =
|
||||
self.resolver.resolve_module_path_in_items(db, mod_path).take_types()
|
||||
{
|
||||
let parent_hir_name = parent_hir_path.segments().get(1).map(|it| it.name);
|
||||
let module = crate::Module { id };
|
||||
if module
|
||||
.scope(db, None)
|
||||
.into_iter()
|
||||
.any(|(name, _)| Some(&name) == parent_hir_name)
|
||||
{
|
||||
let parent_hir_name =
|
||||
parent_hir_path.segments().get(1).map(|it| it.name);
|
||||
let module = crate::Module { id };
|
||||
if module
|
||||
.scope(db, None)
|
||||
.into_iter()
|
||||
.any(|(name, _)| Some(&name) == parent_hir_name)
|
||||
{
|
||||
return Some((
|
||||
PathResolution::Def(ModuleDef::Module(module)),
|
||||
None,
|
||||
));
|
||||
};
|
||||
}
|
||||
return Some((PathResolution::Def(ModuleDef::Module(module)), None));
|
||||
};
|
||||
}
|
||||
Some((it, None))
|
||||
}
|
||||
@ -1282,22 +1277,22 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
db: &'db dyn HirDatabase,
|
||||
macro_expr: InFile<&ast::MacroExpr>,
|
||||
) -> bool {
|
||||
if let Some((def, body, sm, Some(infer))) = self.body_() {
|
||||
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
|
||||
let mut is_unsafe = false;
|
||||
let mut walk_expr = |expr_id| {
|
||||
unsafe_operations(db, infer, def, body, expr_id, &mut |inside_unsafe_block| {
|
||||
is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
|
||||
})
|
||||
};
|
||||
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)
|
||||
}
|
||||
if let Some((def, body, sm, Some(infer))) = self.body_()
|
||||
&& let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr)
|
||||
{
|
||||
let mut is_unsafe = false;
|
||||
let mut walk_expr = |expr_id| {
|
||||
unsafe_operations(db, infer, def, body, expr_id, &mut |inside_unsafe_block| {
|
||||
is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
|
||||
})
|
||||
};
|
||||
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;
|
||||
}
|
||||
return is_unsafe;
|
||||
}
|
||||
false
|
||||
}
|
||||
@ -1575,12 +1570,11 @@ fn resolve_hir_path_(
|
||||
|
||||
// If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
|
||||
// within the trait's associated types.
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
|
||||
if let Some(type_alias_id) =
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty)
|
||||
&& let Some(type_alias_id) =
|
||||
trait_id.trait_items(db).associated_type_by_name(unresolved.name)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
|
||||
let res = match ty {
|
||||
@ -1726,12 +1720,11 @@ fn resolve_hir_path_qualifier(
|
||||
|
||||
// If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
|
||||
// within the trait's associated types.
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
|
||||
if let Some(type_alias_id) =
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty)
|
||||
&& let Some(type_alias_id) =
|
||||
trait_id.trait_items(db).associated_type_by_name(unresolved.name)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
|
||||
let res = match ty {
|
||||
|
@ -122,10 +122,10 @@ impl<'db> LookupTable<'db> {
|
||||
}
|
||||
|
||||
// Collapse suggestions if there are many
|
||||
if let Some(res) = &res {
|
||||
if res.len() > self.many_threshold {
|
||||
return Some(vec![Expr::Many(ty.clone())]);
|
||||
}
|
||||
if let Some(res) = &res
|
||||
&& res.len() > self.many_threshold
|
||||
{
|
||||
return Some(vec![Expr::Many(ty.clone())]);
|
||||
}
|
||||
|
||||
res
|
||||
@ -160,10 +160,10 @@ impl<'db> LookupTable<'db> {
|
||||
}
|
||||
|
||||
// Collapse suggestions if there are many
|
||||
if let Some(res) = &res {
|
||||
if res.len() > self.many_threshold {
|
||||
return Some(vec![Expr::Many(ty.clone())]);
|
||||
}
|
||||
if let Some(res) = &res
|
||||
&& res.len() > self.many_threshold
|
||||
{
|
||||
return Some(vec![Expr::Many(ty.clone())]);
|
||||
}
|
||||
|
||||
res
|
||||
|
@ -336,10 +336,10 @@ impl<'db> Expr<'db> {
|
||||
|
||||
if let Expr::Method { func, params, .. } = self {
|
||||
res.extend(params.iter().flat_map(|it| it.traits_used(db)));
|
||||
if let Some(it) = func.as_assoc_item(db) {
|
||||
if let Some(it) = it.container_or_implemented_trait(db) {
|
||||
res.push(it);
|
||||
}
|
||||
if let Some(it) = func.as_assoc_item(db)
|
||||
&& let Some(it) = it.container_or_implemented_trait(db)
|
||||
{
|
||||
res.push(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,10 +82,10 @@ fn fetch_borrowed_types(node: &ast::Adt) -> Option<Vec<ast::RefType>> {
|
||||
record_field_list
|
||||
.fields()
|
||||
.filter_map(|r_field| {
|
||||
if let ast::Type::RefType(ref_type) = r_field.ty()? {
|
||||
if ref_type.lifetime().is_none() {
|
||||
return Some(ref_type);
|
||||
}
|
||||
if let ast::Type::RefType(ref_type) = r_field.ty()?
|
||||
&& ref_type.lifetime().is_none()
|
||||
{
|
||||
return Some(ref_type);
|
||||
}
|
||||
|
||||
None
|
||||
@ -102,10 +102,10 @@ fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option<Vec<ast
|
||||
ast::FieldList::RecordFieldList(record_list) => record_list
|
||||
.fields()
|
||||
.filter_map(|f| {
|
||||
if let ast::Type::RefType(ref_type) = f.ty()? {
|
||||
if ref_type.lifetime().is_none() {
|
||||
return Some(ref_type);
|
||||
}
|
||||
if let ast::Type::RefType(ref_type) = f.ty()?
|
||||
&& ref_type.lifetime().is_none()
|
||||
{
|
||||
return Some(ref_type);
|
||||
}
|
||||
|
||||
None
|
||||
@ -114,10 +114,10 @@ fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option<Vec<ast
|
||||
ast::FieldList::TupleFieldList(tuple_field_list) => tuple_field_list
|
||||
.fields()
|
||||
.filter_map(|f| {
|
||||
if let ast::Type::RefType(ref_type) = f.ty()? {
|
||||
if ref_type.lifetime().is_none() {
|
||||
return Some(ref_type);
|
||||
}
|
||||
if let ast::Type::RefType(ref_type) = f.ty()?
|
||||
&& ref_type.lifetime().is_none()
|
||||
{
|
||||
return Some(ref_type);
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -183,13 +183,11 @@ fn add_missing_impl_members_inner(
|
||||
.clone()
|
||||
.into_iter()
|
||||
.chain(other_items.iter().cloned())
|
||||
.map(either::Either::Right)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut editor = edit.make_editor(impl_def.syntax());
|
||||
if let Some(assoc_item_list) = impl_def.assoc_item_list() {
|
||||
let items = new_assoc_items.into_iter().filter_map(either::Either::right).collect();
|
||||
assoc_item_list.add_items(&mut editor, items);
|
||||
assoc_item_list.add_items(&mut editor, new_assoc_items);
|
||||
} else {
|
||||
let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
|
||||
editor.insert_all(
|
||||
@ -201,14 +199,12 @@ fn add_missing_impl_members_inner(
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
let mut placeholder = None;
|
||||
if let DefaultMethods::No = mode {
|
||||
if let Some(ast::AssocItem::Fn(func)) = &first_new_item {
|
||||
if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
|
||||
&& m.syntax().text() == "todo!()"
|
||||
{
|
||||
placeholder = Some(m);
|
||||
}
|
||||
}
|
||||
if let DefaultMethods::No = mode
|
||||
&& let Some(ast::AssocItem::Fn(func)) = &first_new_item
|
||||
&& let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
|
||||
&& m.syntax().text() == "todo!()"
|
||||
{
|
||||
placeholder = Some(m);
|
||||
}
|
||||
|
||||
if let Some(macro_call) = placeholder {
|
||||
|
@ -207,10 +207,10 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
// negate all tail expressions in the closure body
|
||||
let tail_cb = &mut |e: &_| tail_cb_impl(&mut editor, &make, e);
|
||||
walk_expr(&closure_body, &mut |expr| {
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr {
|
||||
if let Some(ret_expr_arg) = &ret_expr.expr() {
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr
|
||||
&& let Some(ret_expr_arg) = &ret_expr.expr()
|
||||
{
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
});
|
||||
for_each_tail_expr(&closure_body, tail_cb);
|
||||
|
@ -86,12 +86,11 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
e @ ast::Expr::CallExpr(_) => Some(e.clone()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(ast::Expr::CallExpr(call)) = e {
|
||||
if let Some(arg_list) = call.arg_list() {
|
||||
if let Some(arg) = arg_list.args().next() {
|
||||
editor.replace(call.syntax(), arg.syntax());
|
||||
}
|
||||
}
|
||||
if let Some(ast::Expr::CallExpr(call)) = e
|
||||
&& let Some(arg_list) = call.arg_list()
|
||||
&& let Some(arg) = arg_list.args().next()
|
||||
{
|
||||
editor.replace(call.syntax(), arg.syntax());
|
||||
}
|
||||
});
|
||||
let edit = editor.finish();
|
||||
@ -276,12 +275,12 @@ fn is_invalid_body(
|
||||
e @ ast::Expr::CallExpr(_) => Some(e.clone()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(ast::Expr::CallExpr(call)) = e {
|
||||
if let Some(ast::Expr::PathExpr(p)) = call.expr() {
|
||||
let res = p.path().and_then(|p| sema.resolve_path(&p));
|
||||
if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res {
|
||||
return invalid |= v != some_variant;
|
||||
}
|
||||
if let Some(ast::Expr::CallExpr(call)) = e
|
||||
&& let Some(ast::Expr::PathExpr(p)) = call.expr()
|
||||
{
|
||||
let res = p.path().and_then(|p| sema.resolve_path(&p));
|
||||
if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res {
|
||||
return invalid |= v != some_variant;
|
||||
}
|
||||
}
|
||||
invalid = true
|
||||
|
@ -101,21 +101,21 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
// but we need to locate `AstPtr`s inside the body.
|
||||
let mut wrap_body_in_block = true;
|
||||
if let ast::Expr::BlockExpr(block) = &body {
|
||||
if let Some(async_token) = block.async_token() {
|
||||
if !is_async {
|
||||
is_async = true;
|
||||
ret_ty = ret_ty.future_output(ctx.db())?;
|
||||
let token_idx = async_token.index();
|
||||
let whitespace_tokens_after_count = async_token
|
||||
.siblings_with_tokens(Direction::Next)
|
||||
.skip(1)
|
||||
.take_while(|token| token.kind() == SyntaxKind::WHITESPACE)
|
||||
.count();
|
||||
body.syntax().splice_children(
|
||||
token_idx..token_idx + whitespace_tokens_after_count + 1,
|
||||
Vec::new(),
|
||||
);
|
||||
}
|
||||
if let Some(async_token) = block.async_token()
|
||||
&& !is_async
|
||||
{
|
||||
is_async = true;
|
||||
ret_ty = ret_ty.future_output(ctx.db())?;
|
||||
let token_idx = async_token.index();
|
||||
let whitespace_tokens_after_count = async_token
|
||||
.siblings_with_tokens(Direction::Next)
|
||||
.skip(1)
|
||||
.take_while(|token| token.kind() == SyntaxKind::WHITESPACE)
|
||||
.count();
|
||||
body.syntax().splice_children(
|
||||
token_idx..token_idx + whitespace_tokens_after_count + 1,
|
||||
Vec::new(),
|
||||
);
|
||||
}
|
||||
if let Some(gen_token) = block.gen_token() {
|
||||
is_gen = true;
|
||||
@ -513,10 +513,10 @@ fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Exp
|
||||
CaptureKind::MutableRef | CaptureKind::UniqueSharedRef => true,
|
||||
CaptureKind::Move => return place,
|
||||
};
|
||||
if let ast::Expr::PrefixExpr(expr) = &place {
|
||||
if expr.op_kind() == Some(ast::UnaryOp::Deref) {
|
||||
return expr.expr().expect("`display_place_source_code()` produced an invalid expr");
|
||||
}
|
||||
if let ast::Expr::PrefixExpr(expr) = &place
|
||||
&& expr.op_kind() == Some(ast::UnaryOp::Deref)
|
||||
{
|
||||
return expr.expr().expect("`display_place_source_code()` produced an invalid expr");
|
||||
}
|
||||
make::expr_ref(place, needs_mut)
|
||||
}
|
||||
@ -642,11 +642,11 @@ fn peel_blocks_and_refs_and_parens(mut expr: ast::Expr) -> ast::Expr {
|
||||
expr = ast::Expr::cast(parent).unwrap();
|
||||
continue;
|
||||
}
|
||||
if let Some(stmt_list) = ast::StmtList::cast(parent) {
|
||||
if let Some(block) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) {
|
||||
expr = ast::Expr::BlockExpr(block);
|
||||
continue;
|
||||
}
|
||||
if let Some(stmt_list) = ast::StmtList::cast(parent)
|
||||
&& let Some(block) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)
|
||||
{
|
||||
expr = ast::Expr::BlockExpr(block);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -662,12 +662,11 @@ fn expr_of_pat(pat: ast::Pat) -> Option<ast::Expr> {
|
||||
if let Some(let_stmt) = ast::LetStmt::cast(ancestor.clone()) {
|
||||
break 'find_expr let_stmt.initializer();
|
||||
}
|
||||
if ast::MatchArm::can_cast(ancestor.kind()) {
|
||||
if let Some(match_) =
|
||||
if ast::MatchArm::can_cast(ancestor.kind())
|
||||
&& let Some(match_) =
|
||||
ancestor.parent().and_then(|it| it.parent()).and_then(ast::MatchExpr::cast)
|
||||
{
|
||||
break 'find_expr match_.expr();
|
||||
}
|
||||
{
|
||||
break 'find_expr match_.expr();
|
||||
}
|
||||
if ast::ExprStmt::can_cast(ancestor.kind()) {
|
||||
break;
|
||||
|
@ -1,9 +1,7 @@
|
||||
use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait};
|
||||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
ast::{self, AstNode, HasGenericArgs, HasName, make},
|
||||
ted,
|
||||
};
|
||||
use syntax::ast::edit::IndentLevel;
|
||||
use syntax::ast::{self, AstNode, HasGenericArgs, HasName, make};
|
||||
use syntax::syntax_editor::{Element, Position};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists};
|
||||
|
||||
@ -49,11 +47,12 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
};
|
||||
|
||||
let associated_items = impl_.assoc_item_list()?;
|
||||
let associated_l_curly = associated_items.l_curly_token()?;
|
||||
let from_fn = associated_items.assoc_items().find_map(|item| {
|
||||
if let ast::AssocItem::Fn(f) = item {
|
||||
if f.name()?.text() == "from" {
|
||||
return Some(f);
|
||||
}
|
||||
if let ast::AssocItem::Fn(f) = item
|
||||
&& f.name()?.text() == "from"
|
||||
{
|
||||
return Some(f);
|
||||
};
|
||||
None
|
||||
})?;
|
||||
@ -75,30 +74,25 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
"Convert From to TryFrom",
|
||||
impl_.syntax().text_range(),
|
||||
|builder| {
|
||||
let trait_ty = builder.make_mut(trait_ty);
|
||||
let from_fn_return_type = builder.make_mut(from_fn_return_type);
|
||||
let from_fn_name = builder.make_mut(from_fn_name);
|
||||
let tail_expr = builder.make_mut(tail_expr);
|
||||
let return_exprs = return_exprs.map(|r| builder.make_mut(r)).collect_vec();
|
||||
let associated_items = builder.make_mut(associated_items);
|
||||
|
||||
ted::replace(
|
||||
let mut editor = builder.make_editor(impl_.syntax());
|
||||
editor.replace(
|
||||
trait_ty.syntax(),
|
||||
make::ty(&format!("TryFrom<{from_type}>")).syntax().clone_for_update(),
|
||||
);
|
||||
ted::replace(
|
||||
editor.replace(
|
||||
from_fn_return_type.syntax(),
|
||||
make::ty("Result<Self, Self::Error>").syntax().clone_for_update(),
|
||||
);
|
||||
ted::replace(from_fn_name.syntax(), make::name("try_from").syntax().clone_for_update());
|
||||
ted::replace(
|
||||
editor
|
||||
.replace(from_fn_name.syntax(), make::name("try_from").syntax().clone_for_update());
|
||||
editor.replace(
|
||||
tail_expr.syntax(),
|
||||
wrap_ok(tail_expr.clone()).syntax().clone_for_update(),
|
||||
);
|
||||
|
||||
for r in return_exprs {
|
||||
let t = r.expr().unwrap_or_else(make::ext::expr_unit);
|
||||
ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
|
||||
editor.replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
|
||||
}
|
||||
|
||||
let error_type = ast::AssocItem::TypeAlias(make::ty_alias(
|
||||
@ -110,15 +104,24 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
))
|
||||
.clone_for_update();
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let ast::AssocItem::TypeAlias(type_alias) = &error_type {
|
||||
if let Some(ty) = type_alias.ty() {
|
||||
builder.add_placeholder_snippet(cap, ty);
|
||||
}
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let ast::AssocItem::TypeAlias(type_alias) = &error_type
|
||||
&& let Some(ty) = type_alias.ty()
|
||||
{
|
||||
let placeholder = builder.make_placeholder_snippet(cap);
|
||||
editor.add_annotation(ty.syntax(), placeholder);
|
||||
}
|
||||
|
||||
associated_items.add_item_at_start(error_type);
|
||||
let indent = IndentLevel::from_token(&associated_l_curly) + 1;
|
||||
editor.insert_all(
|
||||
Position::after(associated_l_curly),
|
||||
vec![
|
||||
make::tokens::whitespace(&format!("\n{indent}")).syntax_element(),
|
||||
error_type.syntax().syntax_element(),
|
||||
make::tokens::whitespace("\n").syntax_element(),
|
||||
],
|
||||
);
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
|
||||
};
|
||||
|
||||
let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| {
|
||||
if let ast::AssocItem::Fn(f) = item {
|
||||
if f.name()?.text() == "into" {
|
||||
return Some(f);
|
||||
}
|
||||
if let ast::AssocItem::Fn(f) = item
|
||||
&& f.name()?.text() == "into"
|
||||
{
|
||||
return Some(f);
|
||||
};
|
||||
None
|
||||
})?;
|
||||
|
@ -265,10 +265,10 @@ fn replace_body_return_values(body: ast::Expr, struct_name: &str) {
|
||||
|
||||
let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
|
||||
walk_expr(&body, &mut |expr| {
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr {
|
||||
if let Some(ret_expr_arg) = &ret_expr.expr() {
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr
|
||||
&& let Some(ret_expr_arg) = &ret_expr.expr()
|
||||
{
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
});
|
||||
for_each_tail_expr(&body, tail_cb);
|
||||
|
@ -1,9 +1,14 @@
|
||||
use either::Either;
|
||||
use hir::FileRangeWrapper;
|
||||
use ide_db::defs::{Definition, NameRefClass};
|
||||
use std::ops::RangeInclusive;
|
||||
use syntax::{
|
||||
SyntaxKind, SyntaxNode,
|
||||
ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility},
|
||||
match_ast, ted,
|
||||
SyntaxElement, SyntaxKind, SyntaxNode, T, TextSize,
|
||||
ast::{
|
||||
self, AstNode, HasAttrs, HasGenericParams, HasVisibility, syntax_factory::SyntaxFactory,
|
||||
},
|
||||
match_ast,
|
||||
syntax_editor::{Element, Position, SyntaxEditor},
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
|
||||
@ -71,7 +76,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
|
||||
Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
|
||||
};
|
||||
let target = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
|
||||
|
||||
let syntax = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax());
|
||||
acc.add(
|
||||
AssistId::refactor_rewrite("convert_tuple_struct_to_named_struct"),
|
||||
"Convert to named struct",
|
||||
@ -79,58 +84,55 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
|
||||
|edit| {
|
||||
let names = generate_names(tuple_fields.fields());
|
||||
edit_field_references(ctx, edit, tuple_fields.fields(), &names);
|
||||
let mut editor = edit.make_editor(syntax);
|
||||
edit_struct_references(ctx, edit, strukt_def, &names);
|
||||
edit_struct_def(ctx, edit, &strukt_or_variant, tuple_fields, names);
|
||||
edit_struct_def(&mut editor, &strukt_or_variant, tuple_fields, names);
|
||||
edit.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn edit_struct_def(
|
||||
ctx: &AssistContext<'_>,
|
||||
edit: &mut SourceChangeBuilder,
|
||||
editor: &mut SyntaxEditor,
|
||||
strukt: &Either<ast::Struct, ast::Variant>,
|
||||
tuple_fields: ast::TupleFieldList,
|
||||
names: Vec<ast::Name>,
|
||||
) {
|
||||
let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| {
|
||||
let field = ast::make::record_field(f.visibility(), name, f.ty()?).clone_for_update();
|
||||
ted::insert_all(
|
||||
ted::Position::first_child_of(field.syntax()),
|
||||
let field = ast::make::record_field(f.visibility(), name, f.ty()?);
|
||||
let mut field_editor = SyntaxEditor::new(field.syntax().clone());
|
||||
field_editor.insert_all(
|
||||
Position::first_child_of(field.syntax()),
|
||||
f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
|
||||
);
|
||||
Some(field)
|
||||
ast::RecordField::cast(field_editor.finish().new_root().clone())
|
||||
});
|
||||
let record_fields = ast::make::record_field_list(record_fields);
|
||||
let tuple_fields_text_range = tuple_fields.syntax().text_range();
|
||||
|
||||
edit.edit_file(ctx.vfs_file_id());
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let record_fields = make.record_field_list(record_fields);
|
||||
let tuple_fields_before = Position::before(tuple_fields.syntax());
|
||||
|
||||
if let Either::Left(strukt) = strukt {
|
||||
if let Some(w) = strukt.where_clause() {
|
||||
edit.delete(w.syntax().text_range());
|
||||
edit.insert(
|
||||
tuple_fields_text_range.start(),
|
||||
ast::make::tokens::single_newline().text(),
|
||||
);
|
||||
edit.insert(tuple_fields_text_range.start(), w.syntax().text());
|
||||
editor.delete(w.syntax());
|
||||
let mut insert_element = Vec::new();
|
||||
insert_element.push(ast::make::tokens::single_newline().syntax_element());
|
||||
insert_element.push(w.syntax().clone_for_update().syntax_element());
|
||||
if w.syntax().last_token().is_none_or(|t| t.kind() != SyntaxKind::COMMA) {
|
||||
edit.insert(tuple_fields_text_range.start(), ",");
|
||||
insert_element.push(ast::make::token(T![,]).into());
|
||||
}
|
||||
edit.insert(
|
||||
tuple_fields_text_range.start(),
|
||||
ast::make::tokens::single_newline().text(),
|
||||
);
|
||||
insert_element.push(ast::make::tokens::single_newline().syntax_element());
|
||||
editor.insert_all(tuple_fields_before, insert_element);
|
||||
} else {
|
||||
edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
|
||||
editor.insert(tuple_fields_before, ast::make::tokens::single_space());
|
||||
}
|
||||
if let Some(t) = strukt.semicolon_token() {
|
||||
edit.delete(t.text_range());
|
||||
editor.delete(t);
|
||||
}
|
||||
} else {
|
||||
edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
|
||||
editor.insert(tuple_fields_before, ast::make::tokens::single_space());
|
||||
}
|
||||
|
||||
edit.replace(tuple_fields_text_range, record_fields.to_string());
|
||||
editor.replace(tuple_fields.syntax(), record_fields.syntax());
|
||||
}
|
||||
|
||||
fn edit_struct_references(
|
||||
@ -145,27 +147,22 @@ fn edit_struct_references(
|
||||
};
|
||||
let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
|
||||
|
||||
let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
|
||||
let edit_node = |node: SyntaxNode| -> Option<SyntaxNode> {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
match_ast! {
|
||||
match node {
|
||||
ast::TupleStructPat(tuple_struct_pat) => {
|
||||
let file_range = ctx.sema.original_range_opt(&node)?;
|
||||
edit.edit_file(file_range.file_id.file_id(ctx.db()));
|
||||
edit.replace(
|
||||
file_range.range,
|
||||
ast::make::record_pat_with_fields(
|
||||
tuple_struct_pat.path()?,
|
||||
ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
|
||||
|(pat, name)| {
|
||||
ast::make::record_pat_field(
|
||||
ast::make::name_ref(&name.to_string()),
|
||||
pat,
|
||||
)
|
||||
},
|
||||
), None),
|
||||
)
|
||||
.to_string(),
|
||||
);
|
||||
Some(make.record_pat_with_fields(
|
||||
tuple_struct_pat.path()?,
|
||||
ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
|
||||
|(pat, name)| {
|
||||
ast::make::record_pat_field(
|
||||
ast::make::name_ref(&name.to_string()),
|
||||
pat,
|
||||
)
|
||||
},
|
||||
), None),
|
||||
).syntax().clone())
|
||||
},
|
||||
// for tuple struct creations like Foo(42)
|
||||
ast::CallExpr(call_expr) => {
|
||||
@ -181,10 +178,8 @@ fn edit_struct_references(
|
||||
}
|
||||
|
||||
let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;
|
||||
|
||||
edit.replace(
|
||||
ctx.sema.original_range(&node).range,
|
||||
ast::make::record_expr(
|
||||
Some(
|
||||
make.record_expr(
|
||||
path,
|
||||
ast::make::record_expr_field_list(arg_list.args().zip(names).map(
|
||||
|(expr, name)| {
|
||||
@ -194,25 +189,58 @@ fn edit_struct_references(
|
||||
)
|
||||
},
|
||||
)),
|
||||
)
|
||||
.to_string(),
|
||||
);
|
||||
).syntax().clone()
|
||||
)
|
||||
},
|
||||
_ => return None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
};
|
||||
|
||||
for (file_id, refs) in usages {
|
||||
edit.edit_file(file_id.file_id(ctx.db()));
|
||||
for r in refs {
|
||||
for node in r.name.syntax().ancestors() {
|
||||
if edit_node(edit, node).is_some() {
|
||||
break;
|
||||
let source = ctx.sema.parse(file_id);
|
||||
let source = source.syntax();
|
||||
|
||||
let mut editor = edit.make_editor(source);
|
||||
for r in refs.iter().rev() {
|
||||
if let Some((old_node, new_node)) = r
|
||||
.name
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.find_map(|node| Some((node.clone(), edit_node(node.clone())?)))
|
||||
{
|
||||
if let Some(old_node) = ctx.sema.original_syntax_node_rooted(&old_node) {
|
||||
editor.replace(old_node, new_node);
|
||||
} else {
|
||||
let FileRangeWrapper { file_id: _, range } = ctx.sema.original_range(&old_node);
|
||||
let parent = source.covering_element(range);
|
||||
match parent {
|
||||
SyntaxElement::Token(token) => {
|
||||
editor.replace(token, new_node.syntax_element());
|
||||
}
|
||||
SyntaxElement::Node(parent_node) => {
|
||||
// replace the part of macro
|
||||
// ```
|
||||
// foo!(a, Test::A(0));
|
||||
// ^^^^^^^^^^^^^^^ // parent_node
|
||||
// ^^^^^^^^^^ // replace_range
|
||||
// ```
|
||||
let start = parent_node
|
||||
.children_with_tokens()
|
||||
.find(|t| t.text_range().contains(range.start()));
|
||||
let end = parent_node
|
||||
.children_with_tokens()
|
||||
.find(|t| t.text_range().contains(range.end() - TextSize::new(1)));
|
||||
if let (Some(start), Some(end)) = (start, end) {
|
||||
let replace_range = RangeInclusive::new(start, end);
|
||||
editor.replace_all(replace_range, vec![new_node.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
edit.add_file_edits(file_id.file_id(ctx.db()), editor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,22 +258,28 @@ fn edit_field_references(
|
||||
let def = Definition::Field(field);
|
||||
let usages = def.usages(&ctx.sema).all();
|
||||
for (file_id, refs) in usages {
|
||||
edit.edit_file(file_id.file_id(ctx.db()));
|
||||
let source = ctx.sema.parse(file_id);
|
||||
let source = source.syntax();
|
||||
let mut editor = edit.make_editor(source);
|
||||
for r in refs {
|
||||
if let Some(name_ref) = r.name.as_name_ref() {
|
||||
edit.replace(ctx.sema.original_range(name_ref.syntax()).range, name.text());
|
||||
if let Some(name_ref) = r.name.as_name_ref()
|
||||
&& let Some(original) = ctx.sema.original_ast_node(name_ref.clone())
|
||||
{
|
||||
editor.replace(original.syntax(), name.syntax());
|
||||
}
|
||||
}
|
||||
edit.add_file_edits(file_id.file_id(ctx.db()), editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
fields
|
||||
.enumerate()
|
||||
.map(|(i, _)| {
|
||||
let idx = i + 1;
|
||||
ast::make::name(&format!("field{idx}"))
|
||||
make.name(&format!("field{idx}"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -1013,8 +1047,7 @@ where
|
||||
pub struct $0Foo(#[my_custom_attr] u32);
|
||||
"#,
|
||||
r#"
|
||||
pub struct Foo { #[my_custom_attr]
|
||||
field1: u32 }
|
||||
pub struct Foo { #[my_custom_attr]field1: u32 }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -100,10 +100,10 @@ fn is_bool_literal_expr(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
expr: &ast::Expr,
|
||||
) -> Option<ArmBodyExpression> {
|
||||
if let ast::Expr::Literal(lit) = expr {
|
||||
if let ast::LiteralKind::Bool(b) = lit.kind() {
|
||||
return Some(ArmBodyExpression::Literal(b));
|
||||
}
|
||||
if let ast::Expr::Literal(lit) = expr
|
||||
&& let ast::LiteralKind::Bool(b) = lit.kind()
|
||||
{
|
||||
return Some(ArmBodyExpression::Literal(b));
|
||||
}
|
||||
|
||||
if !sema.type_of_expr(expr)?.original.is_bool() {
|
||||
|
@ -106,73 +106,73 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast) {
|
||||
if let_stmt.let_else().is_none() {
|
||||
let pat = let_stmt.pat()?;
|
||||
acc.add(
|
||||
AssistId::refactor_rewrite("desugar_try_expr_let_else"),
|
||||
"Replace try expression with let else",
|
||||
target,
|
||||
|builder| {
|
||||
let make = SyntaxFactory::with_mappings();
|
||||
let mut editor = builder.make_editor(let_stmt.syntax());
|
||||
if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast)
|
||||
&& let_stmt.let_else().is_none()
|
||||
{
|
||||
let pat = let_stmt.pat()?;
|
||||
acc.add(
|
||||
AssistId::refactor_rewrite("desugar_try_expr_let_else"),
|
||||
"Replace try expression with let else",
|
||||
target,
|
||||
|builder| {
|
||||
let make = SyntaxFactory::with_mappings();
|
||||
let mut editor = builder.make_editor(let_stmt.syntax());
|
||||
|
||||
let indent_level = IndentLevel::from_node(let_stmt.syntax());
|
||||
let new_let_stmt = make.let_else_stmt(
|
||||
try_enum.happy_pattern(pat),
|
||||
let_stmt.ty(),
|
||||
expr,
|
||||
make.block_expr(
|
||||
iter::once(
|
||||
make.expr_stmt(
|
||||
make.expr_return(Some(match try_enum {
|
||||
TryEnum::Option => make.expr_path(make.ident_path("None")),
|
||||
TryEnum::Result => make
|
||||
.expr_call(
|
||||
make.expr_path(make.ident_path("Err")),
|
||||
make.arg_list(iter::once(
|
||||
match ctx.config.expr_fill_default {
|
||||
ExprFillDefaultMode::Todo => make
|
||||
.expr_macro(
|
||||
make.ident_path("todo"),
|
||||
make.token_tree(
|
||||
syntax::SyntaxKind::L_PAREN,
|
||||
[],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
ExprFillDefaultMode::Underscore => {
|
||||
make.expr_underscore().into()
|
||||
}
|
||||
ExprFillDefaultMode::Default => make
|
||||
.expr_macro(
|
||||
make.ident_path("todo"),
|
||||
make.token_tree(
|
||||
syntax::SyntaxKind::L_PAREN,
|
||||
[],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
)),
|
||||
)
|
||||
.into(),
|
||||
}))
|
||||
.indent(indent_level + 1)
|
||||
.into(),
|
||||
)
|
||||
let indent_level = IndentLevel::from_node(let_stmt.syntax());
|
||||
let new_let_stmt = make.let_else_stmt(
|
||||
try_enum.happy_pattern(pat),
|
||||
let_stmt.ty(),
|
||||
expr,
|
||||
make.block_expr(
|
||||
iter::once(
|
||||
make.expr_stmt(
|
||||
make.expr_return(Some(match try_enum {
|
||||
TryEnum::Option => make.expr_path(make.ident_path("None")),
|
||||
TryEnum::Result => make
|
||||
.expr_call(
|
||||
make.expr_path(make.ident_path("Err")),
|
||||
make.arg_list(iter::once(
|
||||
match ctx.config.expr_fill_default {
|
||||
ExprFillDefaultMode::Todo => make
|
||||
.expr_macro(
|
||||
make.ident_path("todo"),
|
||||
make.token_tree(
|
||||
syntax::SyntaxKind::L_PAREN,
|
||||
[],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
ExprFillDefaultMode::Underscore => {
|
||||
make.expr_underscore().into()
|
||||
}
|
||||
ExprFillDefaultMode::Default => make
|
||||
.expr_macro(
|
||||
make.ident_path("todo"),
|
||||
make.token_tree(
|
||||
syntax::SyntaxKind::L_PAREN,
|
||||
[],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
)),
|
||||
)
|
||||
.into(),
|
||||
}))
|
||||
.indent(indent_level + 1)
|
||||
.into(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
.indent(indent_level),
|
||||
);
|
||||
editor.replace(let_stmt.syntax(), new_let_stmt.syntax());
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
.indent(indent_level),
|
||||
);
|
||||
editor.replace(let_stmt.syntax(), new_let_stmt.syntax());
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
);
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
@ -272,16 +272,16 @@ impl Refs {
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|r| {
|
||||
if let Definition::Trait(tr) = r.def {
|
||||
if tr.items(ctx.db()).into_iter().any(|ai| {
|
||||
if let Definition::Trait(tr) = r.def
|
||||
&& tr.items(ctx.db()).into_iter().any(|ai| {
|
||||
if let AssocItem::Function(f) = ai {
|
||||
def_is_referenced_in(Definition::Function(f), ctx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
def_is_referenced_in(r.def, ctx)
|
||||
|
@ -175,10 +175,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
|
||||
let fn_def = format_function(ctx, module, &fun, old_indent).clone_for_update();
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(name) = fn_def.name() {
|
||||
builder.add_tabstop_before(cap, name);
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(name) = fn_def.name()
|
||||
{
|
||||
builder.add_tabstop_before(cap, name);
|
||||
}
|
||||
|
||||
let fn_def = match fun.self_param_adt(ctx) {
|
||||
@ -289,10 +289,10 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
|
||||
|
||||
// Covering element returned the parent block of one or multiple statements that have been selected
|
||||
if let Some(stmt_list) = ast::StmtList::cast(node.clone()) {
|
||||
if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) {
|
||||
if block_expr.syntax().text_range() == selection_range {
|
||||
return FunctionBody::from_expr(block_expr.into());
|
||||
}
|
||||
if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)
|
||||
&& block_expr.syntax().text_range() == selection_range
|
||||
{
|
||||
return FunctionBody::from_expr(block_expr.into());
|
||||
}
|
||||
|
||||
// Extract the full statements.
|
||||
@ -915,11 +915,10 @@ impl FunctionBody {
|
||||
ast::Fn(fn_) => {
|
||||
let func = sema.to_def(&fn_)?;
|
||||
let mut ret_ty = func.ret_type(sema.db);
|
||||
if func.is_async(sema.db) {
|
||||
if let Some(async_ret) = func.async_ret_type(sema.db) {
|
||||
if func.is_async(sema.db)
|
||||
&& let Some(async_ret) = func.async_ret_type(sema.db) {
|
||||
ret_ty = async_ret;
|
||||
}
|
||||
}
|
||||
(fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(ret_ty))
|
||||
},
|
||||
ast::Static(statik) => {
|
||||
@ -1172,19 +1171,19 @@ impl GenericParent {
|
||||
/// Search `parent`'s ancestors for items with potentially applicable generic parameters
|
||||
fn generic_parents(parent: &SyntaxNode) -> Vec<GenericParent> {
|
||||
let mut list = Vec::new();
|
||||
if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) {
|
||||
if let ast::Item::Fn(ref fn_) = parent_item {
|
||||
if let Some(parent_parent) =
|
||||
parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast)
|
||||
{
|
||||
match parent_parent {
|
||||
ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
|
||||
ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
|
||||
_ => (),
|
||||
}
|
||||
if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast)
|
||||
&& let ast::Item::Fn(ref fn_) = parent_item
|
||||
{
|
||||
if let Some(parent_parent) =
|
||||
parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast)
|
||||
{
|
||||
match parent_parent {
|
||||
ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
|
||||
ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
|
||||
_ => (),
|
||||
}
|
||||
list.push(GenericParent::Fn(fn_.clone()));
|
||||
}
|
||||
list.push(GenericParent::Fn(fn_.clone()));
|
||||
}
|
||||
list
|
||||
}
|
||||
@ -1337,10 +1336,10 @@ fn locals_defined_in_body(
|
||||
// see https://github.com/rust-lang/rust-analyzer/pull/7535#discussion_r570048550
|
||||
let mut res = FxIndexSet::default();
|
||||
body.walk_pat(&mut |pat| {
|
||||
if let ast::Pat::IdentPat(pat) = pat {
|
||||
if let Some(local) = sema.to_def(&pat) {
|
||||
res.insert(local);
|
||||
}
|
||||
if let ast::Pat::IdentPat(pat) = pat
|
||||
&& let Some(local) = sema.to_def(&pat)
|
||||
{
|
||||
res.insert(local);
|
||||
}
|
||||
});
|
||||
res
|
||||
@ -1445,11 +1444,11 @@ fn impl_type_name(impl_node: &ast::Impl) -> Option<String> {
|
||||
fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
|
||||
let parent_match_arm = body.parent().and_then(ast::MatchArm::cast);
|
||||
|
||||
if let Some(parent_match_arm) = parent_match_arm {
|
||||
if parent_match_arm.comma_token().is_none() {
|
||||
let parent_match_arm = builder.make_mut(parent_match_arm);
|
||||
ted::append_child_raw(parent_match_arm.syntax(), make::token(T![,]));
|
||||
}
|
||||
if let Some(parent_match_arm) = parent_match_arm
|
||||
&& parent_match_arm.comma_token().is_none()
|
||||
{
|
||||
let parent_match_arm = builder.make_mut(parent_match_arm);
|
||||
ted::append_child_raw(parent_match_arm.syntax(), make::token(T![,]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2120,30 +2119,30 @@ fn update_external_control_flow(handler: &FlowHandler<'_>, syntax: &SyntaxNode)
|
||||
_ => {}
|
||||
},
|
||||
WalkEvent::Leave(e) => {
|
||||
if nested_scope.is_none() {
|
||||
if let Some(expr) = ast::Expr::cast(e.clone()) {
|
||||
match expr {
|
||||
ast::Expr::ReturnExpr(return_expr) => {
|
||||
let expr = return_expr.expr();
|
||||
if let Some(replacement) = make_rewritten_flow(handler, expr) {
|
||||
ted::replace(return_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
if nested_scope.is_none()
|
||||
&& let Some(expr) = ast::Expr::cast(e.clone())
|
||||
{
|
||||
match expr {
|
||||
ast::Expr::ReturnExpr(return_expr) => {
|
||||
let expr = return_expr.expr();
|
||||
if let Some(replacement) = make_rewritten_flow(handler, expr) {
|
||||
ted::replace(return_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => {
|
||||
let expr = break_expr.expr();
|
||||
if let Some(replacement) = make_rewritten_flow(handler, expr) {
|
||||
ted::replace(break_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
}
|
||||
ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => {
|
||||
let expr = break_expr.expr();
|
||||
if let Some(replacement) = make_rewritten_flow(handler, expr) {
|
||||
ted::replace(break_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => {
|
||||
if let Some(replacement) = make_rewritten_flow(handler, None) {
|
||||
ted::replace(continue_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// do nothing
|
||||
}
|
||||
ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => {
|
||||
if let Some(replacement) = make_rewritten_flow(handler, None) {
|
||||
ted::replace(continue_expr.syntax(), replacement.syntax())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,13 +69,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
||||
|
||||
let mut impl_parent: Option<ast::Impl> = None;
|
||||
let mut impl_child_count: usize = 0;
|
||||
if let Some(parent_assoc_list) = node.parent() {
|
||||
if let Some(parent_impl) = parent_assoc_list.parent() {
|
||||
if let Some(impl_) = ast::Impl::cast(parent_impl) {
|
||||
impl_child_count = parent_assoc_list.children().count();
|
||||
impl_parent = Some(impl_);
|
||||
}
|
||||
}
|
||||
if let Some(parent_assoc_list) = node.parent()
|
||||
&& let Some(parent_impl) = parent_assoc_list.parent()
|
||||
&& let Some(impl_) = ast::Impl::cast(parent_impl)
|
||||
{
|
||||
impl_child_count = parent_assoc_list.children().count();
|
||||
impl_parent = Some(impl_);
|
||||
}
|
||||
|
||||
let mut curr_parent_module: Option<ast::Module> = None;
|
||||
@ -436,10 +435,10 @@ impl Module {
|
||||
}
|
||||
})
|
||||
.for_each(|(node, def)| {
|
||||
if node_set.insert(node.to_string()) {
|
||||
if let Some(import) = self.process_def_in_sel(def, &node, &module, ctx) {
|
||||
check_intersection_and_push(&mut imports_to_remove, import);
|
||||
}
|
||||
if node_set.insert(node.to_string())
|
||||
&& let Some(import) = self.process_def_in_sel(def, &node, &module, ctx)
|
||||
{
|
||||
check_intersection_and_push(&mut imports_to_remove, import);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -542,15 +541,16 @@ impl Module {
|
||||
import_path_to_be_removed = Some(text_range);
|
||||
}
|
||||
|
||||
if def_in_mod && def_out_sel {
|
||||
if let Some(first_path_in_use_tree) = use_tree_str.last() {
|
||||
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
|
||||
if !first_path_in_use_tree_str.contains("super")
|
||||
&& !first_path_in_use_tree_str.contains("crate")
|
||||
{
|
||||
let super_path = make::ext::ident_path("super");
|
||||
use_tree_str.push(super_path);
|
||||
}
|
||||
if def_in_mod
|
||||
&& def_out_sel
|
||||
&& let Some(first_path_in_use_tree) = use_tree_str.last()
|
||||
{
|
||||
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
|
||||
if !first_path_in_use_tree_str.contains("super")
|
||||
&& !first_path_in_use_tree_str.contains("crate")
|
||||
{
|
||||
let super_path = make::ext::ident_path("super");
|
||||
use_tree_str.push(super_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,12 +563,11 @@ impl Module {
|
||||
if let Some(mut use_tree_paths) = use_tree_paths {
|
||||
use_tree_paths.reverse();
|
||||
|
||||
if uses_exist_out_sel || !uses_exist_in_sel || !def_in_mod || !def_out_sel {
|
||||
if let Some(first_path_in_use_tree) = use_tree_paths.first() {
|
||||
if first_path_in_use_tree.to_string().contains("super") {
|
||||
use_tree_paths.insert(0, make::ext::ident_path("super"));
|
||||
}
|
||||
}
|
||||
if (uses_exist_out_sel || !uses_exist_in_sel || !def_in_mod || !def_out_sel)
|
||||
&& let Some(first_path_in_use_tree) = use_tree_paths.first()
|
||||
&& first_path_in_use_tree.to_string().contains("super")
|
||||
{
|
||||
use_tree_paths.insert(0, make::ext::ident_path("super"));
|
||||
}
|
||||
|
||||
let is_item = matches!(
|
||||
@ -691,11 +690,9 @@ fn check_def_in_mod_and_out_sel(
|
||||
_ => source.file_id.original_file(ctx.db()).file_id(ctx.db()) == curr_file_id,
|
||||
};
|
||||
|
||||
if have_same_parent {
|
||||
if let ModuleSource::Module(module_) = source.value {
|
||||
let in_sel = !selection_range.contains_range(module_.syntax().text_range());
|
||||
return (have_same_parent, in_sel);
|
||||
}
|
||||
if have_same_parent && let ModuleSource::Module(module_) = source.value {
|
||||
let in_sel = !selection_range.contains_range(module_.syntax().text_range());
|
||||
return (have_same_parent, in_sel);
|
||||
}
|
||||
|
||||
return (have_same_parent, false);
|
||||
@ -772,12 +769,12 @@ fn get_use_tree_paths_from_path(
|
||||
.filter(|x| x.to_string() != path.to_string())
|
||||
.filter_map(ast::UseTree::cast)
|
||||
.find_map(|use_tree| {
|
||||
if let Some(upper_tree_path) = use_tree.path() {
|
||||
if upper_tree_path.to_string() != path.to_string() {
|
||||
use_tree_str.push(upper_tree_path.clone());
|
||||
get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
|
||||
return Some(use_tree);
|
||||
}
|
||||
if let Some(upper_tree_path) = use_tree.path()
|
||||
&& upper_tree_path.to_string() != path.to_string()
|
||||
{
|
||||
use_tree_str.push(upper_tree_path.clone());
|
||||
get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
|
||||
return Some(use_tree);
|
||||
}
|
||||
None
|
||||
})?;
|
||||
@ -786,11 +783,11 @@ fn get_use_tree_paths_from_path(
|
||||
}
|
||||
|
||||
fn add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax::SyntaxElement>) {
|
||||
if vis.is_none() {
|
||||
if let Some(node_or_token) = node_or_token_opt {
|
||||
let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
|
||||
ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax());
|
||||
}
|
||||
if vis.is_none()
|
||||
&& let Some(node_or_token) = node_or_token_opt
|
||||
{
|
||||
let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
|
||||
ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,12 +215,12 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
|
||||
ast::GenericParam::LifetimeParam(lt)
|
||||
if matches!(token.kind(), T![lifetime_ident]) =>
|
||||
{
|
||||
if let Some(lt) = lt.lifetime() {
|
||||
if lt.text().as_str() == token.text() {
|
||||
*tag = true;
|
||||
tagged_one = true;
|
||||
break;
|
||||
}
|
||||
if let Some(lt) = lt.lifetime()
|
||||
&& lt.text().as_str() == token.text()
|
||||
{
|
||||
*tag = true;
|
||||
tagged_one = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
param if matches!(token.kind(), T![ident]) => {
|
||||
|
@ -72,10 +72,10 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None)))
|
||||
.clone_for_update();
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(name) = ty_alias.name() {
|
||||
edit.add_annotation(name.syntax(), builder.make_tabstop_before(cap));
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(name) = ty_alias.name()
|
||||
{
|
||||
edit.add_annotation(name.syntax(), builder.make_tabstop_before(cap));
|
||||
}
|
||||
|
||||
let indent = IndentLevel::from_node(node);
|
||||
@ -111,17 +111,17 @@ fn collect_used_generics<'gp>(
|
||||
match ty {
|
||||
ast::Type::PathType(ty) => {
|
||||
if let Some(path) = ty.path() {
|
||||
if let Some(name_ref) = path.as_single_name_ref() {
|
||||
if let Some(param) = known_generics.iter().find(|gp| {
|
||||
if let Some(name_ref) = path.as_single_name_ref()
|
||||
&& let Some(param) = known_generics.iter().find(|gp| {
|
||||
match gp {
|
||||
ast::GenericParam::ConstParam(cp) => cp.name(),
|
||||
ast::GenericParam::TypeParam(tp) => tp.name(),
|
||||
_ => None,
|
||||
}
|
||||
.is_some_and(|n| n.text() == name_ref.text())
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
})
|
||||
{
|
||||
generics.push(param);
|
||||
}
|
||||
generics.extend(
|
||||
path.segments()
|
||||
@ -160,20 +160,18 @@ fn collect_used_generics<'gp>(
|
||||
.and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
),
|
||||
ast::Type::ArrayType(ar) => {
|
||||
if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) {
|
||||
if let Some(path) = p.path() {
|
||||
if let Some(name_ref) = path.as_single_name_ref() {
|
||||
if let Some(param) = known_generics.iter().find(|gp| {
|
||||
if let ast::GenericParam::ConstParam(cp) = gp {
|
||||
cp.name().is_some_and(|n| n.text() == name_ref.text())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr())
|
||||
&& let Some(path) = p.path()
|
||||
&& let Some(name_ref) = path.as_single_name_ref()
|
||||
&& let Some(param) = known_generics.iter().find(|gp| {
|
||||
if let ast::GenericParam::ConstParam(cp) = gp {
|
||||
cp.name().is_some_and(|n| n.text() == name_ref.text())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
generics.push(param);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -404,11 +404,10 @@ impl Anchor {
|
||||
}
|
||||
if let Some(expr) =
|
||||
node.parent().and_then(ast::StmtList::cast).and_then(|it| it.tail_expr())
|
||||
&& expr.syntax() == &node
|
||||
{
|
||||
if expr.syntax() == &node {
|
||||
cov_mark::hit!(test_extract_var_last_expr);
|
||||
return Some(Anchor::Before(node));
|
||||
}
|
||||
cov_mark::hit!(test_extract_var_last_expr);
|
||||
return Some(Anchor::Before(node));
|
||||
}
|
||||
|
||||
if let Some(parent) = node.parent() {
|
||||
@ -427,10 +426,10 @@ impl Anchor {
|
||||
}
|
||||
|
||||
if let Some(stmt) = ast::Stmt::cast(node.clone()) {
|
||||
if let ast::Stmt::ExprStmt(stmt) = stmt {
|
||||
if stmt.expr().as_ref() == Some(to_extract) {
|
||||
return Some(Anchor::Replace(stmt));
|
||||
}
|
||||
if let ast::Stmt::ExprStmt(stmt) = stmt
|
||||
&& stmt.expr().as_ref() == Some(to_extract)
|
||||
{
|
||||
return Some(Anchor::Replace(stmt));
|
||||
}
|
||||
return Some(Anchor::Before(node));
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ use hir::{HasCrate, HasVisibility};
|
||||
use ide_db::{FxHashSet, path_transform::PathTransform};
|
||||
use syntax::{
|
||||
ast::{
|
||||
self, AstNode, HasGenericParams, HasName, HasVisibility as _, edit_in_place::Indent, make,
|
||||
self, AstNode, HasGenericParams, HasName, HasVisibility as _,
|
||||
edit::{AstNodeEdit, IndentLevel},
|
||||
make,
|
||||
},
|
||||
ted,
|
||||
syntax_editor::Position,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -165,54 +167,66 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|
||||
is_unsafe,
|
||||
is_gen,
|
||||
)
|
||||
.clone_for_update();
|
||||
.indent(IndentLevel(1));
|
||||
let item = ast::AssocItem::Fn(f.clone());
|
||||
|
||||
// Get the impl to update, or create one if we need to.
|
||||
let impl_def = match impl_def {
|
||||
Some(impl_def) => edit.make_mut(impl_def),
|
||||
let mut editor = edit.make_editor(strukt.syntax());
|
||||
let fn_: Option<ast::AssocItem> = match impl_def {
|
||||
Some(impl_def) => match impl_def.assoc_item_list() {
|
||||
Some(assoc_item_list) => {
|
||||
let item = item.indent(IndentLevel::from_node(impl_def.syntax()));
|
||||
assoc_item_list.add_items(&mut editor, vec![item.clone()]);
|
||||
Some(item)
|
||||
}
|
||||
None => {
|
||||
let assoc_item_list = make::assoc_item_list(Some(vec![item]));
|
||||
editor.insert(
|
||||
Position::last_child_of(impl_def.syntax()),
|
||||
assoc_item_list.syntax(),
|
||||
);
|
||||
assoc_item_list.assoc_items().next()
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let name = &strukt_name.to_string();
|
||||
let ty_params = strukt.generic_param_list();
|
||||
let ty_args = ty_params.as_ref().map(|it| it.to_generic_args());
|
||||
let where_clause = strukt.where_clause();
|
||||
let assoc_item_list = make::assoc_item_list(Some(vec![item]));
|
||||
|
||||
let impl_def = make::impl_(
|
||||
ty_params,
|
||||
ty_args,
|
||||
make::ty_path(make::ext::ident_path(name)),
|
||||
where_clause,
|
||||
None,
|
||||
Some(assoc_item_list),
|
||||
)
|
||||
.clone_for_update();
|
||||
|
||||
// Fixup impl_def indentation
|
||||
let indent = strukt.indent_level();
|
||||
impl_def.reindent_to(indent);
|
||||
let impl_def = impl_def.indent(indent);
|
||||
|
||||
// Insert the impl block.
|
||||
let strukt = edit.make_mut(strukt.clone());
|
||||
ted::insert_all(
|
||||
ted::Position::after(strukt.syntax()),
|
||||
editor.insert_all(
|
||||
Position::after(strukt.syntax()),
|
||||
vec![
|
||||
make::tokens::whitespace(&format!("\n\n{indent}")).into(),
|
||||
impl_def.syntax().clone().into(),
|
||||
],
|
||||
);
|
||||
|
||||
impl_def
|
||||
impl_def.assoc_item_list().and_then(|list| list.assoc_items().next())
|
||||
}
|
||||
};
|
||||
|
||||
// Fixup function indentation.
|
||||
// FIXME: Should really be handled by `AssocItemList::add_item`
|
||||
f.reindent_to(impl_def.indent_level() + 1);
|
||||
|
||||
let assoc_items = impl_def.get_or_create_assoc_item_list();
|
||||
assoc_items.add_item(f.clone().into());
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
edit.add_tabstop_before(cap, f)
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(fn_) = fn_
|
||||
{
|
||||
let tabstop = edit.make_tabstop_before(cap);
|
||||
editor.add_annotation(fn_.syntax(), tabstop);
|
||||
}
|
||||
edit.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
@ -148,11 +148,11 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<St
|
||||
let self_name = self_name(ast_func);
|
||||
|
||||
format_to!(example, "use {use_path};\n\n");
|
||||
if let Some(self_name) = &self_name {
|
||||
if let Some(mut_) = is_ref_mut_self(ast_func) {
|
||||
let mut_ = if mut_ { "mut " } else { "" };
|
||||
format_to!(example, "let {mut_}{self_name} = ;\n");
|
||||
}
|
||||
if let Some(self_name) = &self_name
|
||||
&& let Some(mut_) = is_ref_mut_self(ast_func)
|
||||
{
|
||||
let mut_ = if mut_ { "mut " } else { "" };
|
||||
format_to!(example, "let {mut_}{self_name} = ;\n");
|
||||
}
|
||||
for param_name in &ref_mut_params {
|
||||
format_to!(example, "let mut {param_name} = ;\n");
|
||||
@ -170,10 +170,10 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<St
|
||||
format_to!(example, "{function_call};\n");
|
||||
}
|
||||
// Check the mutated values
|
||||
if let Some(self_name) = &self_name {
|
||||
if is_ref_mut_self(ast_func) == Some(true) {
|
||||
format_to!(example, "assert_eq!({self_name}, );");
|
||||
}
|
||||
if let Some(self_name) = &self_name
|
||||
&& is_ref_mut_self(ast_func) == Some(true)
|
||||
{
|
||||
format_to!(example, "assert_eq!({self_name}, );");
|
||||
}
|
||||
for param_name in &ref_mut_params {
|
||||
format_to!(example, "assert_eq!({param_name}, );");
|
||||
@ -313,12 +313,28 @@ fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
|
||||
/// `None` if function without a body; some bool to guess if function can panic
|
||||
fn can_panic(ast_func: &ast::Fn) -> Option<bool> {
|
||||
let body = ast_func.body()?.to_string();
|
||||
let can_panic = body.contains("panic!(")
|
||||
// FIXME it would be better to not match `debug_assert*!` macro invocations
|
||||
|| body.contains("assert!(")
|
||||
|| body.contains(".unwrap()")
|
||||
|| body.contains(".expect(");
|
||||
Some(can_panic)
|
||||
let mut iter = body.chars();
|
||||
let assert_postfix = |s| {
|
||||
["!(", "_eq!(", "_ne!(", "_matches!("].iter().any(|postfix| str::starts_with(s, postfix))
|
||||
};
|
||||
|
||||
while !iter.as_str().is_empty() {
|
||||
let s = iter.as_str();
|
||||
iter.next();
|
||||
if s.strip_prefix("debug_assert").is_some_and(assert_postfix) {
|
||||
iter.nth(10);
|
||||
continue;
|
||||
}
|
||||
if s.strip_prefix("assert").is_some_and(assert_postfix)
|
||||
|| s.starts_with("panic!(")
|
||||
|| s.starts_with(".unwrap()")
|
||||
|| s.starts_with(".expect(")
|
||||
{
|
||||
return Some(true);
|
||||
}
|
||||
}
|
||||
|
||||
Some(false)
|
||||
}
|
||||
|
||||
/// Helper function to get the name that should be given to `self` arguments
|
||||
@ -677,6 +693,24 @@ pub fn panics_if(a: bool) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guesses_debug_assert_macro_cannot_panic() {
|
||||
check_assist(
|
||||
generate_documentation_template,
|
||||
r#"
|
||||
pub fn $0debug_panics_if_not(a: bool) {
|
||||
debug_assert!(a == true);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
/// .
|
||||
pub fn debug_panics_if_not(a: bool) {
|
||||
debug_assert!(a == true);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guesses_assert_macro_can_panic() {
|
||||
check_assist(
|
||||
@ -699,6 +733,28 @@ pub fn panics_if_not(a: bool) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guesses_assert_eq_macro_can_panic() {
|
||||
check_assist(
|
||||
generate_documentation_template,
|
||||
r#"
|
||||
pub fn $0panics_if_not(a: bool) {
|
||||
assert_eq!(a, true);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
/// .
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if .
|
||||
pub fn panics_if_not(a: bool) {
|
||||
assert_eq!(a, true);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guesses_unwrap_can_panic() {
|
||||
check_assist(
|
||||
|
@ -111,10 +111,10 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
],
|
||||
);
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(name) = ty_alias.name() {
|
||||
edit.add_annotation(name.syntax(), builder.make_placeholder_snippet(cap));
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(name) = ty_alias.name()
|
||||
{
|
||||
edit.add_annotation(name.syntax(), builder.make_placeholder_snippet(cap));
|
||||
}
|
||||
|
||||
builder.add_file_edits(ctx.vfs_file_id(), edit);
|
||||
|
@ -70,10 +70,10 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let TargetInfo { target_module, adt_info, target, file } =
|
||||
fn_target_info(ctx, path, &call, fn_name)?;
|
||||
|
||||
if let Some(m) = target_module {
|
||||
if !is_editable_crate(m.krate(), ctx.db()) {
|
||||
return None;
|
||||
}
|
||||
if let Some(m) = target_module
|
||||
&& !is_editable_crate(m.krate(), ctx.db())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let function_builder =
|
||||
|
@ -433,12 +433,11 @@ fn build_source_change(
|
||||
new_fn.indent(1.into());
|
||||
|
||||
// Insert a tabstop only for last method we generate
|
||||
if i == record_fields_count - 1 {
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(name) = new_fn.name() {
|
||||
builder.add_tabstop_before(cap, name);
|
||||
}
|
||||
}
|
||||
if i == record_fields_count - 1
|
||||
&& let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(name) = new_fn.name()
|
||||
{
|
||||
builder.add_tabstop_before(cap, name);
|
||||
}
|
||||
|
||||
assoc_item_list.add_item(new_fn.clone().into());
|
||||
|
@ -58,11 +58,11 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
|
||||
|
||||
let mut editor = edit.make_editor(nominal.syntax());
|
||||
// Add a tabstop after the left curly brace
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) {
|
||||
let tabstop = edit.make_tabstop_after(cap);
|
||||
editor.add_annotation(l_curly, tabstop);
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token())
|
||||
{
|
||||
let tabstop = edit.make_tabstop_after(cap);
|
||||
editor.add_annotation(l_curly, tabstop);
|
||||
}
|
||||
|
||||
insert_impl(&mut editor, &impl_, &nominal);
|
||||
@ -201,7 +201,6 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
&impl_,
|
||||
&target_scope,
|
||||
);
|
||||
let assoc_items = assoc_items.into_iter().map(either::Either::Right).collect();
|
||||
let assoc_item_list = make::assoc_item_list(Some(assoc_items));
|
||||
make_impl_(Some(assoc_item_list))
|
||||
};
|
||||
|
@ -104,7 +104,14 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
format!("Generate `{trait_new}` impl from this `{trait_name}` trait"),
|
||||
target,
|
||||
|edit| {
|
||||
edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}"));
|
||||
edit.insert(
|
||||
target.start(),
|
||||
if ctx.config.snippet_cap.is_some() {
|
||||
format!("$0{impl_def}\n\n{indent}")
|
||||
} else {
|
||||
format!("{impl_def}\n\n{indent}")
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -161,7 +168,10 @@ fn process_ret_type(ref_ty: &ast::RetType) -> Option<ast::Type> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
use crate::{
|
||||
AssistConfig,
|
||||
tests::{TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_with_config},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -402,6 +412,43 @@ impl<T> Index$0<i32> for [T; 3] {}
|
||||
pub trait AsRef<T: ?Sized> {}
|
||||
|
||||
impl AsRef$0<i32> for [T; 3] {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_snippets() {
|
||||
check_assist_with_config(
|
||||
generate_mut_trait_impl,
|
||||
AssistConfig { snippet_cap: None, ..TEST_CONFIG },
|
||||
r#"
|
||||
//- minicore: index
|
||||
pub enum Axis { X = 0, Y = 1, Z = 2 }
|
||||
|
||||
impl<T> core::ops::Index$0<Axis> for [T; 3] {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, index: Axis) -> &Self::Output {
|
||||
&self[index as usize]
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
pub enum Axis { X = 0, Y = 1, Z = 2 }
|
||||
|
||||
impl<T> core::ops::IndexMut<Axis> for [T; 3] {
|
||||
fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
|
||||
&mut self[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::Index<Axis> for [T; 3] {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, index: Axis) -> &Self::Output {
|
||||
&self[index as usize]
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
||||
);
|
||||
fn_.syntax().clone()
|
||||
} else {
|
||||
let items = vec![either::Either::Right(ast::AssocItem::Fn(fn_))];
|
||||
let items = vec![ast::AssocItem::Fn(fn_)];
|
||||
let list = make::assoc_item_list(Some(items));
|
||||
editor.insert(Position::after(impl_def.syntax()), list.syntax());
|
||||
list.syntax().clone()
|
||||
@ -176,7 +176,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
||||
} else {
|
||||
// Generate a new impl to add the method to
|
||||
let indent_level = strukt.indent_level();
|
||||
let body = vec![either::Either::Right(ast::AssocItem::Fn(fn_))];
|
||||
let body = vec![ast::AssocItem::Fn(fn_)];
|
||||
let list = make::assoc_item_list(Some(body));
|
||||
let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list));
|
||||
|
||||
|
@ -2,12 +2,8 @@ use crate::assist_context::{AssistContext, Assists};
|
||||
use ide_db::assists::AssistId;
|
||||
use syntax::{
|
||||
AstNode, SyntaxKind, T,
|
||||
ast::{
|
||||
self, HasGenericParams, HasName, HasVisibility,
|
||||
edit_in_place::{HasVisibilityEdit, Indent},
|
||||
make,
|
||||
},
|
||||
ted::{self, Position},
|
||||
ast::{self, HasGenericParams, HasName, HasVisibility, edit_in_place::Indent, make},
|
||||
syntax_editor::{Position, SyntaxEditor},
|
||||
};
|
||||
|
||||
// NOTES :
|
||||
@ -88,8 +84,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
return None;
|
||||
}
|
||||
|
||||
let assoc_items = impl_ast.assoc_item_list()?;
|
||||
let first_element = assoc_items.assoc_items().next();
|
||||
let impl_assoc_items = impl_ast.assoc_item_list()?;
|
||||
let first_element = impl_assoc_items.assoc_items().next();
|
||||
first_element.as_ref()?;
|
||||
|
||||
let impl_name = impl_ast.self_ty()?;
|
||||
@ -99,20 +95,16 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
"Generate trait from impl",
|
||||
impl_ast.syntax().text_range(),
|
||||
|builder| {
|
||||
let impl_ast = builder.make_mut(impl_ast);
|
||||
let trait_items = assoc_items.clone_for_update();
|
||||
let impl_items = builder.make_mut(assoc_items);
|
||||
let impl_name = builder.make_mut(impl_name);
|
||||
|
||||
trait_items.assoc_items().for_each(|item| {
|
||||
strip_body(&item);
|
||||
remove_items_visibility(&item);
|
||||
});
|
||||
|
||||
impl_items.assoc_items().for_each(|item| {
|
||||
remove_items_visibility(&item);
|
||||
});
|
||||
let trait_items: ast::AssocItemList = {
|
||||
let trait_items = impl_assoc_items.clone_subtree();
|
||||
let mut trait_items_editor = SyntaxEditor::new(trait_items.syntax().clone());
|
||||
|
||||
trait_items.assoc_items().for_each(|item| {
|
||||
strip_body(&mut trait_items_editor, &item);
|
||||
remove_items_visibility(&mut trait_items_editor, &item);
|
||||
});
|
||||
ast::AssocItemList::cast(trait_items_editor.finish().new_root().clone()).unwrap()
|
||||
};
|
||||
let trait_ast = make::trait_(
|
||||
false,
|
||||
"NewTrait",
|
||||
@ -130,6 +122,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
trait_name_ref.syntax().clone().into(),
|
||||
make::tokens::single_space().into(),
|
||||
make::token(T![for]).into(),
|
||||
make::tokens::single_space().into(),
|
||||
];
|
||||
|
||||
if let Some(params) = impl_ast.generic_param_list() {
|
||||
@ -137,10 +130,15 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
elements.insert(1, gen_args.syntax().clone().into());
|
||||
}
|
||||
|
||||
ted::insert_all(Position::before(impl_name.syntax()), elements);
|
||||
let mut editor = builder.make_editor(impl_ast.syntax());
|
||||
impl_assoc_items.assoc_items().for_each(|item| {
|
||||
remove_items_visibility(&mut editor, &item);
|
||||
});
|
||||
|
||||
editor.insert_all(Position::before(impl_name.syntax()), elements);
|
||||
|
||||
// Insert trait before TraitImpl
|
||||
ted::insert_all_raw(
|
||||
editor.insert_all(
|
||||
Position::before(impl_ast.syntax()),
|
||||
vec![
|
||||
trait_ast.syntax().clone().into(),
|
||||
@ -150,11 +148,12 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
|
||||
// Link the trait name & trait ref names together as a placeholder snippet group
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
builder.add_placeholder_snippet_group(
|
||||
cap,
|
||||
vec![trait_name.syntax().clone(), trait_name_ref.syntax().clone()],
|
||||
);
|
||||
let placeholder = builder.make_placeholder_snippet(cap);
|
||||
editor.add_annotation(trait_name.syntax(), placeholder);
|
||||
editor.add_annotation(trait_name_ref.syntax(), placeholder);
|
||||
}
|
||||
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
);
|
||||
|
||||
@ -162,31 +161,33 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
|
||||
}
|
||||
|
||||
/// `E0449` Trait items always share the visibility of their trait
|
||||
fn remove_items_visibility(item: &ast::AssocItem) {
|
||||
fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) {
|
||||
if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) {
|
||||
if let Some(vis) = has_vis.visibility()
|
||||
&& let Some(token) = vis.syntax().next_sibling_or_token()
|
||||
&& token.kind() == SyntaxKind::WHITESPACE
|
||||
{
|
||||
ted::remove(token);
|
||||
editor.delete(token);
|
||||
}
|
||||
if let Some(vis) = has_vis.visibility() {
|
||||
editor.delete(vis.syntax());
|
||||
}
|
||||
has_vis.set_visibility(None);
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_body(item: &ast::AssocItem) {
|
||||
if let ast::AssocItem::Fn(f) = item {
|
||||
if let Some(body) = f.body() {
|
||||
// In contrast to function bodies, we want to see no ws before a semicolon.
|
||||
// So let's remove them if we see any.
|
||||
if let Some(prev) = body.syntax().prev_sibling_or_token() {
|
||||
if prev.kind() == SyntaxKind::WHITESPACE {
|
||||
ted::remove(prev);
|
||||
}
|
||||
}
|
||||
|
||||
ted::replace(body.syntax(), make::tokens::semicolon());
|
||||
fn strip_body(editor: &mut SyntaxEditor, item: &ast::AssocItem) {
|
||||
if let ast::AssocItem::Fn(f) = item
|
||||
&& let Some(body) = f.body()
|
||||
{
|
||||
// In contrast to function bodies, we want to see no ws before a semicolon.
|
||||
// So let's remove them if we see any.
|
||||
if let Some(prev) = body.syntax().prev_sibling_or_token()
|
||||
&& prev.kind() == SyntaxKind::WHITESPACE
|
||||
{
|
||||
editor.delete(prev);
|
||||
}
|
||||
|
||||
editor.replace(body.syntax(), make::tokens::semicolon());
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -393,19 +393,17 @@ fn inline(
|
||||
// `FileReference` incorrect
|
||||
if let Some(imp) =
|
||||
sema.ancestors_with_macros(fn_body.syntax().clone()).find_map(ast::Impl::cast)
|
||||
&& !node.syntax().ancestors().any(|anc| &anc == imp.syntax())
|
||||
&& let Some(t) = imp.self_ty()
|
||||
{
|
||||
if !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) {
|
||||
if let Some(t) = imp.self_ty() {
|
||||
while let Some(self_tok) = body
|
||||
.syntax()
|
||||
.descendants_with_tokens()
|
||||
.filter_map(NodeOrToken::into_token)
|
||||
.find(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
|
||||
{
|
||||
let replace_with = t.clone_subtree().syntax().clone_for_update();
|
||||
ted::replace(self_tok, replace_with);
|
||||
}
|
||||
}
|
||||
while let Some(self_tok) = body
|
||||
.syntax()
|
||||
.descendants_with_tokens()
|
||||
.filter_map(NodeOrToken::into_token)
|
||||
.find(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
|
||||
{
|
||||
let replace_with = t.clone_subtree().syntax().clone_for_update();
|
||||
ted::replace(self_tok, replace_with);
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,10 +413,10 @@ fn inline(
|
||||
for stmt in fn_body.statements() {
|
||||
if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {
|
||||
for has_token in let_stmt.syntax().children_with_tokens() {
|
||||
if let Some(node) = has_token.as_node() {
|
||||
if let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) {
|
||||
func_let_vars.insert(ident_pat.syntax().text().to_string());
|
||||
}
|
||||
if let Some(node) = has_token.as_node()
|
||||
&& let Some(ident_pat) = ast::IdentPat::cast(node.to_owned())
|
||||
{
|
||||
func_let_vars.insert(ident_pat.syntax().text().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -534,16 +532,15 @@ fn inline(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(generic_arg_list) = generic_arg_list.clone() {
|
||||
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
||||
{
|
||||
body.reindent_to(IndentLevel(0));
|
||||
if let Some(new_body) = ast::BlockExpr::cast(
|
||||
PathTransform::function_call(target, source, function, generic_arg_list)
|
||||
.apply(body.syntax()),
|
||||
) {
|
||||
body = new_body;
|
||||
}
|
||||
if let Some(generic_arg_list) = generic_arg_list.clone()
|
||||
&& let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
||||
{
|
||||
body.reindent_to(IndentLevel(0));
|
||||
if let Some(new_body) = ast::BlockExpr::cast(
|
||||
PathTransform::function_call(target, source, function, generic_arg_list)
|
||||
.apply(body.syntax()),
|
||||
) {
|
||||
body = new_body;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,11 @@ use ide_db::{
|
||||
search::FileReference,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use syntax::ast::syntax_factory::SyntaxFactory;
|
||||
use syntax::syntax_editor::SyntaxEditor;
|
||||
use syntax::{
|
||||
AstNode, NodeOrToken, SyntaxNode,
|
||||
ast::{self, HasGenericParams, HasName, make},
|
||||
ted,
|
||||
ast::{self, HasGenericParams, HasName},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -68,37 +69,41 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
let mut definition_deleted = false;
|
||||
|
||||
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
|
||||
builder.edit_file(file_id);
|
||||
let source = ctx.sema.parse(file_id);
|
||||
let mut editor = builder.make_editor(source.syntax());
|
||||
|
||||
let (path_types, path_type_uses) =
|
||||
split_refs_and_uses(builder, refs, |path_type| {
|
||||
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
|
||||
});
|
||||
|
||||
path_type_uses
|
||||
.iter()
|
||||
.flat_map(ast_to_remove_for_path_in_use_stmt)
|
||||
.for_each(|x| builder.delete(x.syntax().text_range()));
|
||||
.for_each(|x| editor.delete(x.syntax()));
|
||||
|
||||
for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
|
||||
let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
|
||||
let target = path_type.syntax().text_range();
|
||||
let replacement =
|
||||
inline(&ast_alias, &path_type)?.replace_generic(&concrete_type);
|
||||
let target = path_type.syntax().clone();
|
||||
Some((target, replacement))
|
||||
}) {
|
||||
builder.replace(target, replacement);
|
||||
editor.replace(target, replacement);
|
||||
}
|
||||
|
||||
if file_id == ctx.vfs_file_id() {
|
||||
builder.delete(ast_alias.syntax().text_range());
|
||||
if file_id.file_id(ctx.db()) == ctx.vfs_file_id() {
|
||||
editor.delete(ast_alias.syntax());
|
||||
definition_deleted = true;
|
||||
}
|
||||
builder.add_file_edits(file_id.file_id(ctx.db()), editor);
|
||||
};
|
||||
|
||||
for (file_id, refs) in usages.into_iter() {
|
||||
inline_refs_for_file(file_id.file_id(ctx.db()), refs);
|
||||
inline_refs_for_file(file_id, refs);
|
||||
}
|
||||
if !definition_deleted {
|
||||
builder.edit_file(ctx.vfs_file_id());
|
||||
builder.delete(ast_alias.syntax().text_range());
|
||||
let mut editor = builder.make_editor(ast_alias.syntax());
|
||||
editor.delete(ast_alias.syntax());
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor)
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -146,23 +151,26 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
||||
}
|
||||
}
|
||||
|
||||
let target = alias_instance.syntax().text_range();
|
||||
|
||||
acc.add(
|
||||
AssistId::refactor_inline("inline_type_alias"),
|
||||
"Inline type alias",
|
||||
target,
|
||||
|builder| builder.replace(target, replacement.to_text(&concrete_type)),
|
||||
alias_instance.syntax().text_range(),
|
||||
|builder| {
|
||||
let mut editor = builder.make_editor(alias_instance.syntax());
|
||||
let replace = replacement.replace_generic(&concrete_type);
|
||||
editor.replace(alias_instance.syntax(), replace);
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
impl Replacement {
|
||||
fn to_text(&self, concrete_type: &ast::Type) -> String {
|
||||
fn replace_generic(&self, concrete_type: &ast::Type) -> SyntaxNode {
|
||||
match self {
|
||||
Replacement::Generic { lifetime_map, const_and_type_map } => {
|
||||
create_replacement(lifetime_map, const_and_type_map, concrete_type)
|
||||
}
|
||||
Replacement::Plain => concrete_type.to_string(),
|
||||
Replacement::Plain => concrete_type.syntax().clone_subtree().clone_for_update(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,8 +207,8 @@ impl LifetimeMap {
|
||||
alias_generics: &ast::GenericParamList,
|
||||
) -> Option<Self> {
|
||||
let mut inner = FxHashMap::default();
|
||||
|
||||
let wildcard_lifetime = make::lifetime("'_");
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let wildcard_lifetime = make.lifetime("'_");
|
||||
let lifetimes = alias_generics
|
||||
.lifetime_params()
|
||||
.filter_map(|lp| lp.lifetime())
|
||||
@ -299,15 +307,14 @@ fn create_replacement(
|
||||
lifetime_map: &LifetimeMap,
|
||||
const_and_type_map: &ConstAndTypeMap,
|
||||
concrete_type: &ast::Type,
|
||||
) -> String {
|
||||
let updated_concrete_type = concrete_type.clone_for_update();
|
||||
let mut replacements = Vec::new();
|
||||
let mut removals = Vec::new();
|
||||
) -> SyntaxNode {
|
||||
let updated_concrete_type = concrete_type.syntax().clone_subtree();
|
||||
let mut editor = SyntaxEditor::new(updated_concrete_type.clone());
|
||||
|
||||
for syntax in updated_concrete_type.syntax().descendants() {
|
||||
let syntax_string = syntax.to_string();
|
||||
let syntax_str = syntax_string.as_str();
|
||||
let mut replacements: Vec<(SyntaxNode, SyntaxNode)> = Vec::new();
|
||||
let mut removals: Vec<NodeOrToken<SyntaxNode, _>> = Vec::new();
|
||||
|
||||
for syntax in updated_concrete_type.descendants() {
|
||||
if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) {
|
||||
if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) {
|
||||
if new_lifetime.text() == "'_" {
|
||||
@ -322,12 +329,16 @@ fn create_replacement(
|
||||
|
||||
replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
|
||||
}
|
||||
} else if let Some(replacement_syntax) = const_and_type_map.0.get(syntax_str) {
|
||||
} else if let Some(name_ref) = ast::NameRef::cast(syntax.clone()) {
|
||||
let Some(replacement_syntax) = const_and_type_map.0.get(&name_ref.to_string()) else {
|
||||
continue;
|
||||
};
|
||||
let new_string = replacement_syntax.to_string();
|
||||
let new = if new_string == "_" {
|
||||
make::wildcard_pat().syntax().clone_for_update()
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
make.wildcard_pat().syntax().clone()
|
||||
} else {
|
||||
replacement_syntax.clone_for_update()
|
||||
replacement_syntax.clone()
|
||||
};
|
||||
|
||||
replacements.push((syntax.clone(), new));
|
||||
@ -335,14 +346,13 @@ fn create_replacement(
|
||||
}
|
||||
|
||||
for (old, new) in replacements {
|
||||
ted::replace(old, new);
|
||||
editor.replace(old, new);
|
||||
}
|
||||
|
||||
for syntax in removals {
|
||||
ted::remove(syntax);
|
||||
editor.delete(syntax);
|
||||
}
|
||||
|
||||
updated_concrete_type.to_string()
|
||||
editor.finish().new_root().clone()
|
||||
}
|
||||
|
||||
fn get_type_alias(ctx: &AssistContext<'_>, path: &ast::PathType) -> Option<ast::TypeAlias> {
|
||||
@ -377,12 +387,15 @@ impl ConstOrTypeGeneric {
|
||||
}
|
||||
|
||||
fn replacement_value(&self) -> Option<SyntaxNode> {
|
||||
Some(match self {
|
||||
ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
|
||||
ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
|
||||
ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
|
||||
ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
|
||||
})
|
||||
Some(
|
||||
match self {
|
||||
ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
|
||||
ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
|
||||
ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
|
||||
ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
|
||||
}
|
||||
.clone_for_update(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,10 +43,10 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
let db = ctx.db();
|
||||
let const_: ast::Const = ctx.find_node_at_offset()?;
|
||||
// Don't show the assist when the cursor is at the const's body.
|
||||
if let Some(body) = const_.body() {
|
||||
if body.syntax().text_range().contains(ctx.offset()) {
|
||||
return None;
|
||||
}
|
||||
if let Some(body) = const_.body()
|
||||
&& body.syntax().text_range().contains(ctx.offset())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let parent_fn = const_.syntax().ancestors().find_map(ast::Fn::cast)?;
|
||||
|
@ -62,10 +62,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Some(parent) = tgt.syntax().parent() {
|
||||
if matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) {
|
||||
return None;
|
||||
}
|
||||
if let Some(parent) = tgt.syntax().parent()
|
||||
&& matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let target = tgt.syntax().text_range();
|
||||
|
||||
@ -90,10 +90,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
let mut editor = SyntaxEditor::new(edit_tgt);
|
||||
for (stmt, rhs) in assignments {
|
||||
let mut stmt = stmt.syntax().clone();
|
||||
if let Some(parent) = stmt.parent() {
|
||||
if ast::ExprStmt::cast(parent.clone()).is_some() {
|
||||
stmt = parent.clone();
|
||||
}
|
||||
if let Some(parent) = stmt.parent()
|
||||
&& ast::ExprStmt::cast(parent.clone()).is_some()
|
||||
{
|
||||
stmt = parent.clone();
|
||||
}
|
||||
editor.replace(stmt, rhs.syntax());
|
||||
}
|
||||
|
@ -80,15 +80,15 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
||||
// parse inside string to escape `"`
|
||||
let escaped = value.escape_default().to_string();
|
||||
let suffix = string_suffix(token.text()).unwrap_or_default();
|
||||
if let Some(offsets) = token.quote_offsets() {
|
||||
if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped {
|
||||
let end_quote = offsets.quotes.1;
|
||||
let end_quote =
|
||||
TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix));
|
||||
edit.replace(offsets.quotes.0, "\"");
|
||||
edit.replace(end_quote, "\"");
|
||||
return;
|
||||
}
|
||||
if let Some(offsets) = token.quote_offsets()
|
||||
&& token.text()[offsets.contents - token.syntax().text_range().start()] == escaped
|
||||
{
|
||||
let end_quote = offsets.quotes.1;
|
||||
let end_quote =
|
||||
TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix));
|
||||
edit.replace(offsets.quotes.0, "\"");
|
||||
edit.replace(end_quote, "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
edit.replace(token.syntax().text_range(), format!("\"{escaped}\"{suffix}"));
|
||||
|
@ -221,11 +221,7 @@ fn impl_def_from_trait(
|
||||
} else {
|
||||
Some(first.clone())
|
||||
};
|
||||
let items = first_item
|
||||
.into_iter()
|
||||
.chain(other.iter().cloned())
|
||||
.map(either::Either::Right)
|
||||
.collect();
|
||||
let items = first_item.into_iter().chain(other.iter().cloned()).collect();
|
||||
make::assoc_item_list(Some(items))
|
||||
} else {
|
||||
make::assoc_item_list(None)
|
||||
|
@ -102,10 +102,10 @@ pub(crate) fn replace_qualified_name_with_use(
|
||||
|
||||
fn drop_generic_args(path: &ast::Path) -> ast::Path {
|
||||
let path = path.clone_for_update();
|
||||
if let Some(segment) = path.segment() {
|
||||
if let Some(generic_args) = segment.generic_arg_list() {
|
||||
ted::remove(generic_args.syntax());
|
||||
}
|
||||
if let Some(segment) = path.segment()
|
||||
&& let Some(generic_args) = segment.generic_arg_list()
|
||||
{
|
||||
ted::remove(generic_args.syntax());
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -41,10 +41,10 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
||||
return None;
|
||||
}
|
||||
// Do nothing if the method is a member of trait.
|
||||
if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast) {
|
||||
if impl_.trait_().is_some() {
|
||||
return None;
|
||||
}
|
||||
if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast)
|
||||
&& impl_.trait_().is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
// Remove the `async` keyword plus whitespace after it, if any.
|
||||
|
@ -72,20 +72,20 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
let mut exprs_to_unwrap = Vec::new();
|
||||
let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e);
|
||||
walk_expr(&body_expr, &mut |expr| {
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr {
|
||||
if let Some(ret_expr_arg) = &ret_expr.expr() {
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
if let ast::Expr::ReturnExpr(ret_expr) = expr
|
||||
&& let Some(ret_expr_arg) = &ret_expr.expr()
|
||||
{
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
});
|
||||
for_each_tail_expr(&body_expr, tail_cb);
|
||||
|
||||
let is_unit_type = is_unit_type(&happy_type);
|
||||
if is_unit_type {
|
||||
if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() {
|
||||
if token.kind() == SyntaxKind::WHITESPACE {
|
||||
editor.delete(token);
|
||||
}
|
||||
if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token()
|
||||
&& token.kind() == SyntaxKind::WHITESPACE
|
||||
{
|
||||
editor.delete(token);
|
||||
}
|
||||
|
||||
editor.delete(ret_type.syntax());
|
||||
@ -162,10 +162,10 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
if let Some(final_placeholder) = final_placeholder {
|
||||
editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap));
|
||||
}
|
||||
if let Some(cap) = ctx.config.snippet_cap
|
||||
&& let Some(final_placeholder) = final_placeholder
|
||||
{
|
||||
editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap));
|
||||
}
|
||||
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
|
@ -47,10 +47,10 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
||||
if tuple_pat.fields().count() != tuple_init.fields().count() {
|
||||
return None;
|
||||
}
|
||||
if let Some(tys) = &tuple_ty {
|
||||
if tuple_pat.fields().count() != tys.fields().count() {
|
||||
return None;
|
||||
}
|
||||
if let Some(tys) = &tuple_ty
|
||||
&& tuple_pat.fields().count() != tys.fields().count()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let parent = let_kw.parent()?;
|
||||
|
@ -101,24 +101,24 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
let mut exprs_to_wrap = Vec::new();
|
||||
let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
|
||||
walk_expr(&body_expr, &mut |expr| {
|
||||
if let Expr::ReturnExpr(ret_expr) = expr {
|
||||
if let Some(ret_expr_arg) = &ret_expr.expr() {
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
if let Expr::ReturnExpr(ret_expr) = expr
|
||||
&& let Some(ret_expr_arg) = &ret_expr.expr()
|
||||
{
|
||||
for_each_tail_expr(ret_expr_arg, tail_cb);
|
||||
}
|
||||
});
|
||||
for_each_tail_expr(&body_expr, tail_cb);
|
||||
|
||||
for ret_expr_arg in exprs_to_wrap {
|
||||
if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) {
|
||||
if ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) {
|
||||
// The type is already correct, don't wrap it.
|
||||
// We deliberately don't use `could_unify_with_deeply()`, because as long as the outer
|
||||
// enum matches it's okay for us, as we don't trigger the assist if the return type
|
||||
// is already `Option`/`Result`, so mismatched exact type is more likely a mistake
|
||||
// than something intended.
|
||||
continue;
|
||||
}
|
||||
if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg)
|
||||
&& ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty)
|
||||
{
|
||||
// The type is already correct, don't wrap it.
|
||||
// We deliberately don't use `could_unify_with_deeply()`, because as long as the outer
|
||||
// enum matches it's okay for us, as we don't trigger the assist if the return type
|
||||
// is already `Option`/`Result`, so mismatched exact type is more likely a mistake
|
||||
// than something intended.
|
||||
continue;
|
||||
}
|
||||
|
||||
let happy_wrapped = make.expr_call(
|
||||
@ -147,13 +147,13 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
ast::GenericArg::LifetimeArg(_) => false,
|
||||
_ => true,
|
||||
});
|
||||
if let Some(error_type_arg) = error_type_arg {
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
editor.add_annotation(
|
||||
error_type_arg.syntax(),
|
||||
builder.make_placeholder_snippet(cap),
|
||||
);
|
||||
}
|
||||
if let Some(error_type_arg) = error_type_arg
|
||||
&& let Some(cap) = ctx.config.snippet_cap
|
||||
{
|
||||
editor.add_annotation(
|
||||
error_type_arg.syntax(),
|
||||
builder.make_placeholder_snippet(cap),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,13 +200,12 @@ fn wrap_derive(
|
||||
],
|
||||
);
|
||||
|
||||
if let Some(snippet_cap) = ctx.config.snippet_cap {
|
||||
if let Some(first_meta) =
|
||||
if let Some(snippet_cap) = ctx.config.snippet_cap
|
||||
&& let Some(first_meta) =
|
||||
cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
|
||||
{
|
||||
let tabstop = edit.make_tabstop_after(snippet_cap);
|
||||
editor.add_annotation(first_meta, tabstop);
|
||||
}
|
||||
{
|
||||
let tabstop = edit.make_tabstop_after(snippet_cap);
|
||||
editor.add_annotation(first_meta, tabstop);
|
||||
}
|
||||
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
@ -256,13 +255,12 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
|
||||
|
||||
editor.replace(attr.syntax(), cfg_attr.syntax());
|
||||
|
||||
if let Some(snippet_cap) = ctx.config.snippet_cap {
|
||||
if let Some(first_meta) =
|
||||
if let Some(snippet_cap) = ctx.config.snippet_cap
|
||||
&& let Some(first_meta) =
|
||||
cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
|
||||
{
|
||||
let tabstop = edit.make_tabstop_after(snippet_cap);
|
||||
editor.add_annotation(first_meta, tabstop);
|
||||
}
|
||||
{
|
||||
let tabstop = edit.make_tabstop_after(snippet_cap);
|
||||
editor.add_annotation(first_meta, tabstop);
|
||||
}
|
||||
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
|
@ -23,12 +23,11 @@ use syntax::{
|
||||
ast::{
|
||||
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
|
||||
edit::{AstNodeEdit, IndentLevel},
|
||||
edit_in_place::{AttrsOwnerEdit, Removable},
|
||||
edit_in_place::AttrsOwnerEdit,
|
||||
make,
|
||||
syntax_factory::SyntaxFactory,
|
||||
},
|
||||
syntax_editor::SyntaxEditor,
|
||||
ted,
|
||||
syntax_editor::{Removable, SyntaxEditor},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -131,10 +130,10 @@ pub fn filter_assoc_items(
|
||||
if ignore_items == IgnoreAssocItems::DocHiddenAttrPresent
|
||||
&& assoc_item.attrs(sema.db).has_doc_hidden()
|
||||
{
|
||||
if let hir::AssocItem::Function(f) = assoc_item {
|
||||
if !f.has_body(sema.db) {
|
||||
return true;
|
||||
}
|
||||
if let hir::AssocItem::Function(f) = assoc_item
|
||||
&& !f.has_body(sema.db)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -207,7 +206,7 @@ pub fn add_trait_assoc_items_to_impl(
|
||||
stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`");
|
||||
}
|
||||
}
|
||||
original_item.clone_for_update()
|
||||
original_item
|
||||
}
|
||||
.reset_indent();
|
||||
|
||||
@ -221,31 +220,37 @@ pub fn add_trait_assoc_items_to_impl(
|
||||
cloned_item.remove_attrs_and_docs();
|
||||
cloned_item
|
||||
})
|
||||
.map(|item| {
|
||||
match &item {
|
||||
ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
|
||||
let body = AstNodeEdit::indent(
|
||||
&make::block_expr(
|
||||
None,
|
||||
Some(match config.expr_fill_default {
|
||||
ExprFillDefaultMode::Todo => make::ext::expr_todo(),
|
||||
ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
|
||||
ExprFillDefaultMode::Default => make::ext::expr_todo(),
|
||||
}),
|
||||
),
|
||||
IndentLevel::single(),
|
||||
);
|
||||
ted::replace(fn_.get_or_create_body().syntax(), body.syntax());
|
||||
}
|
||||
ast::AssocItem::TypeAlias(type_alias) => {
|
||||
if let Some(type_bound_list) = type_alias.type_bound_list() {
|
||||
type_bound_list.remove()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
.filter_map(|item| match item {
|
||||
ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
|
||||
let fn_ = fn_.clone_subtree();
|
||||
let new_body = &make::block_expr(
|
||||
None,
|
||||
Some(match config.expr_fill_default {
|
||||
ExprFillDefaultMode::Todo => make::ext::expr_todo(),
|
||||
ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
|
||||
ExprFillDefaultMode::Default => make::ext::expr_todo(),
|
||||
}),
|
||||
);
|
||||
let new_body = AstNodeEdit::indent(new_body, IndentLevel::single());
|
||||
let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
|
||||
fn_.replace_or_insert_body(&mut fn_editor, new_body);
|
||||
let new_fn_ = fn_editor.finish().new_root().clone();
|
||||
ast::AssocItem::cast(new_fn_)
|
||||
}
|
||||
AstNodeEdit::indent(&item, new_indent_level)
|
||||
ast::AssocItem::TypeAlias(type_alias) => {
|
||||
let type_alias = type_alias.clone_subtree();
|
||||
if let Some(type_bound_list) = type_alias.type_bound_list() {
|
||||
let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
|
||||
type_bound_list.remove(&mut type_alias_editor);
|
||||
let type_alias = type_alias_editor.finish().new_root().clone();
|
||||
ast::AssocItem::cast(type_alias)
|
||||
} else {
|
||||
Some(ast::AssocItem::TypeAlias(type_alias))
|
||||
}
|
||||
}
|
||||
item => Some(item),
|
||||
})
|
||||
.map(|item| AstNodeEdit::indent(&item, new_indent_level))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -514,10 +519,10 @@ pub(crate) fn find_struct_impl(
|
||||
if !(same_ty && not_trait_impl) { None } else { Some(impl_blk) }
|
||||
});
|
||||
|
||||
if let Some(ref impl_blk) = block {
|
||||
if has_any_fn(impl_blk, names) {
|
||||
return None;
|
||||
}
|
||||
if let Some(ref impl_blk) = block
|
||||
&& has_any_fn(impl_blk, names)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(block)
|
||||
@ -526,12 +531,11 @@ pub(crate) fn find_struct_impl(
|
||||
fn has_any_fn(imp: &ast::Impl, names: &[String]) -> bool {
|
||||
if let Some(il) = imp.assoc_item_list() {
|
||||
for item in il.assoc_items() {
|
||||
if let ast::AssocItem::Fn(f) = item {
|
||||
if let Some(name) = f.name() {
|
||||
if names.iter().any(|n| n.eq_ignore_ascii_case(&name.text())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let ast::AssocItem::Fn(f) = item
|
||||
&& let Some(name) = f.name()
|
||||
&& names.iter().any(|n| n.eq_ignore_ascii_case(&name.text()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1021,12 +1025,12 @@ pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRa
|
||||
pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList {
|
||||
let mut args = vec![];
|
||||
for param in list.params() {
|
||||
if let Some(ast::Pat::IdentPat(pat)) = param.pat() {
|
||||
if let Some(name) = pat.name() {
|
||||
let name = name.to_string();
|
||||
let expr = make::expr_path(make::ext::ident_path(&name));
|
||||
args.push(expr);
|
||||
}
|
||||
if let Some(ast::Pat::IdentPat(pat)) = param.pat()
|
||||
&& let Some(name) = pat.name()
|
||||
{
|
||||
let name = name.to_string();
|
||||
let expr = make::expr_path(make::ext::ident_path(&name));
|
||||
args.push(expr);
|
||||
}
|
||||
}
|
||||
make::arg_list(args)
|
||||
@ -1138,12 +1142,11 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo
|
||||
};
|
||||
match expr {
|
||||
ast::Expr::CallExpr(call) => {
|
||||
if let Some(ast::Expr::PathExpr(path_expr)) = call.expr() {
|
||||
if let Some(PathResolution::Def(ModuleDef::Function(func))) =
|
||||
if let Some(ast::Expr::PathExpr(path_expr)) = call.expr()
|
||||
&& let Some(PathResolution::Def(ModuleDef::Function(func))) =
|
||||
path_expr.path().and_then(|path| sema.resolve_path(&path))
|
||||
{
|
||||
is_const &= func.is_const(sema.db);
|
||||
}
|
||||
{
|
||||
is_const &= func.is_const(sema.db);
|
||||
}
|
||||
}
|
||||
ast::Expr::MethodCallExpr(call) => {
|
||||
|
@ -111,10 +111,11 @@ impl Completions {
|
||||
ctx: &CompletionContext<'_>,
|
||||
super_chain_len: Option<usize>,
|
||||
) {
|
||||
if let Some(len) = super_chain_len {
|
||||
if len > 0 && len < ctx.depth_from_crate_root {
|
||||
self.add_keyword(ctx, "super::");
|
||||
}
|
||||
if let Some(len) = super_chain_len
|
||||
&& len > 0
|
||||
&& len < ctx.depth_from_crate_root
|
||||
{
|
||||
self.add_keyword(ctx, "super::");
|
||||
}
|
||||
}
|
||||
|
||||
@ -643,10 +644,10 @@ fn enum_variants_with_paths(
|
||||
|
||||
let variants = enum_.variants(ctx.db);
|
||||
|
||||
if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
|
||||
if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
|
||||
variants.iter().for_each(|variant| process_variant(*variant));
|
||||
}
|
||||
if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_))
|
||||
&& impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_))
|
||||
{
|
||||
variants.iter().for_each(|variant| process_variant(*variant));
|
||||
}
|
||||
|
||||
for variant in variants {
|
||||
|
@ -258,12 +258,11 @@ fn complete_methods(
|
||||
fn on_trait_method(&mut self, func: hir::Function) -> ControlFlow<()> {
|
||||
// This needs to come before the `seen_methods` test, so that if we see the same method twice,
|
||||
// once as inherent and once not, we will include it.
|
||||
if let ItemContainer::Trait(trait_) = func.container(self.ctx.db) {
|
||||
if self.ctx.exclude_traits.contains(&trait_)
|
||||
|| trait_.complete(self.ctx.db) == Complete::IgnoreMethods
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
if let ItemContainer::Trait(trait_) = func.container(self.ctx.db)
|
||||
&& (self.ctx.exclude_traits.contains(&trait_)
|
||||
|| trait_.complete(self.ctx.db) == Complete::IgnoreMethods)
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
if func.self_param(self.ctx.db).is_some()
|
||||
|
@ -128,10 +128,10 @@ fn params_from_stmt_list_scope(
|
||||
{
|
||||
let module = scope.module().into();
|
||||
scope.process_all_names(&mut |name, def| {
|
||||
if let hir::ScopeDef::Local(local) = def {
|
||||
if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true) {
|
||||
cb(name, ty);
|
||||
}
|
||||
if let hir::ScopeDef::Local(local) = def
|
||||
&& let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true)
|
||||
{
|
||||
cb(name, ty);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user