Merge pull request #2539 from rust-lang/rustc-pull

Rustc pull update
This commit is contained in:
Tshepang Mbambo 2025-08-07 09:06:25 +02:00 committed by GitHub
commit e918b131f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
224 changed files with 5502 additions and 4803 deletions

View File

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

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

View File

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

View File

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

View File

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

View File

@ -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)
});
}
}
_ => {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(());
}
}

View File

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

View File

@ -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, .. } => {

View File

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

View File

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

View File

@ -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());
}
_ => {}
}
}

View File

@ -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(());
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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");

View File

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

View File

@ -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) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(),
);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
})?;

View File

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

View File

@ -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 }
"#,
);
}

View File

@ -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() {

View File

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

View File

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

View File

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

View File

@ -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());
}
}

View File

@ -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]) => {

View File

@ -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(&lt.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);
}
}
_ => (),

View File

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

View File

@ -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);
},
)?;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]
}
}
"#,
);
}

View File

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

View File

@ -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());
};
}

View File

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

View File

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

View File

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

View File

@ -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());
}

View File

@ -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}"));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) => {

View File

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

View File

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

View File

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