mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Auto merge of #13885 - Veykril:bin-op-adjust, r=Veykril
Skip lifetime elision on fn pointers and fn trait types These currently don't work correctly, so it's better to not render them at all there
This commit is contained in:
commit
5033213fc9
5 changed files with 105 additions and 70 deletions
|
@ -334,6 +334,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let (param_tys, ret_ty) = match res {
|
||||
Some(res) => {
|
||||
let adjustments = auto_deref_adjust_steps(&derefs);
|
||||
// FIXME: Handle call adjustments for Fn/FnMut
|
||||
self.write_expr_adj(*callee, adjustments);
|
||||
res
|
||||
}
|
||||
|
|
|
@ -47,7 +47,10 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
|||
// Don't enable the assist if there is a type ascription without any placeholders
|
||||
if let Some(ty) = &ascribed_ty {
|
||||
let mut contains_infer_ty = false;
|
||||
walk_ty(ty, &mut |ty| contains_infer_ty |= matches!(ty, ast::Type::InferType(_)));
|
||||
walk_ty(ty, &mut |ty| {
|
||||
contains_infer_ty |= matches!(ty, ast::Type::InferType(_));
|
||||
false
|
||||
});
|
||||
if !contains_infer_ty {
|
||||
cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified);
|
||||
return None;
|
||||
|
|
|
@ -108,76 +108,80 @@ fn collect_used_generics<'gp>(
|
|||
}
|
||||
|
||||
let mut generics = Vec::new();
|
||||
walk_ty(ty, &mut |ty| 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| {
|
||||
match gp {
|
||||
ast::GenericParam::ConstParam(cp) => cp.name(),
|
||||
ast::GenericParam::TypeParam(tp) => tp.name(),
|
||||
_ => None,
|
||||
}
|
||||
.map_or(false, |n| n.text() == name_ref.text())
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
}
|
||||
generics.extend(
|
||||
path.segments()
|
||||
.filter_map(|seg| seg.generic_arg_list())
|
||||
.flat_map(|it| it.generic_args())
|
||||
.filter_map(|it| match it {
|
||||
ast::GenericArg::LifetimeArg(lt) => {
|
||||
let lt = lt.lifetime()?;
|
||||
known_generics.iter().find(find_lifetime(<.text()))
|
||||
walk_ty(ty, &mut |ty| {
|
||||
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| {
|
||||
match gp {
|
||||
ast::GenericParam::ConstParam(cp) => cp.name(),
|
||||
ast::GenericParam::TypeParam(tp) => tp.name(),
|
||||
_ => None,
|
||||
}
|
||||
_ => None,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::ImplTraitType(impl_ty) => {
|
||||
if let Some(it) = impl_ty.type_bound_list() {
|
||||
generics.extend(
|
||||
it.bounds()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::DynTraitType(dyn_ty) => {
|
||||
if let Some(it) = dyn_ty.type_bound_list() {
|
||||
generics.extend(
|
||||
it.bounds()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::RefType(ref_) => generics.extend(
|
||||
ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
),
|
||||
ast::Type::ArrayType(ar) => {
|
||||
if let Some(expr) = ar.expr() {
|
||||
if let ast::Expr::PathExpr(p) = 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().map_or(false, |n| n.text() == name_ref.text())
|
||||
} else {
|
||||
false
|
||||
.map_or(false, |n| n.text() == name_ref.text())
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
}
|
||||
generics.extend(
|
||||
path.segments()
|
||||
.filter_map(|seg| seg.generic_arg_list())
|
||||
.flat_map(|it| it.generic_args())
|
||||
.filter_map(|it| match it {
|
||||
ast::GenericArg::LifetimeArg(lt) => {
|
||||
let lt = lt.lifetime()?;
|
||||
known_generics.iter().find(find_lifetime(<.text()))
|
||||
}
|
||||
_ => None,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::ImplTraitType(impl_ty) => {
|
||||
if let Some(it) = impl_ty.type_bound_list() {
|
||||
generics.extend(
|
||||
it.bounds()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::DynTraitType(dyn_ty) => {
|
||||
if let Some(it) = dyn_ty.type_bound_list() {
|
||||
generics.extend(
|
||||
it.bounds()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::Type::RefType(ref_) => generics.extend(
|
||||
ref_.lifetime()
|
||||
.and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))),
|
||||
),
|
||||
ast::Type::ArrayType(ar) => {
|
||||
if let Some(expr) = ar.expr() {
|
||||
if let ast::Expr::PathExpr(p) = 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().map_or(false, |n| n.text() == name_ref.text())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
}) {
|
||||
generics.push(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
_ => (),
|
||||
};
|
||||
false
|
||||
});
|
||||
// stable resort to lifetime, type, const
|
||||
generics.sort_by_key(|gp| match gp {
|
||||
|
|
|
@ -173,7 +173,8 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
|
|||
}
|
||||
|
||||
/// Preorder walk all the type's sub types.
|
||||
pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) {
|
||||
// FIXME: Make the control flow more proper
|
||||
pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type) -> bool) {
|
||||
let mut preorder = ty.syntax().preorder();
|
||||
while let Some(event) = preorder.next() {
|
||||
let node = match event {
|
||||
|
@ -184,10 +185,12 @@ pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) {
|
|||
match ast::Type::cast(node) {
|
||||
Some(ty @ ast::Type::MacroType(_)) => {
|
||||
preorder.skip_subtree();
|
||||
cb(ty)
|
||||
cb(ty);
|
||||
}
|
||||
Some(ty) => {
|
||||
cb(ty);
|
||||
if cb(ty) {
|
||||
preorder.skip_subtree();
|
||||
}
|
||||
}
|
||||
// skip const args
|
||||
None if ast::ConstArg::can_cast(kind) => {
|
||||
|
|
|
@ -59,9 +59,14 @@ pub(super) fn hints(
|
|||
r.amp_token(),
|
||||
lifetime,
|
||||
is_elided,
|
||||
))
|
||||
));
|
||||
false
|
||||
}
|
||||
_ => (),
|
||||
ast::Type::FnPtrType(_) => true,
|
||||
ast::Type::PathType(t) => {
|
||||
t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some()
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
});
|
||||
acc
|
||||
|
@ -146,8 +151,13 @@ pub(super) fn hints(
|
|||
is_trivial = false;
|
||||
acc.push(mk_lt_hint(amp, output_lt.to_string()));
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => (),
|
||||
ast::Type::FnPtrType(_) => true,
|
||||
ast::Type::PathType(t) => {
|
||||
t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some()
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +305,20 @@ impl () {
|
|||
// ^^^<'0, '1>
|
||||
// ^'0 ^'1 ^'0
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hints_lifetimes_skip_fn_likes() {
|
||||
check_with_config(
|
||||
InlayHintsConfig {
|
||||
lifetime_elision_hints: LifetimeElisionHints::Always,
|
||||
..TEST_CONFIG
|
||||
},
|
||||
r#"
|
||||
fn fn_ptr(a: fn(&()) -> &()) {}
|
||||
fn fn_trait<>(a: impl Fn(&()) -> &()) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue