mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Merge pull request #19922 from Veykril/push-oxyomxrsplpx
feat: Add `dyn` keyword inlay hints
This commit is contained in:
commit
2dc5aa885a
@ -931,11 +931,12 @@ pub fn new() {
|
|||||||
// PATH_TYPE@23..26
|
// PATH_TYPE@23..26
|
||||||
// PATH@23..26
|
// PATH@23..26
|
||||||
// PATH_SEGMENT@23..26
|
// PATH_SEGMENT@23..26
|
||||||
// L_ANGLE@23..24 "<"
|
// TYPE_ANCHOR@23..26
|
||||||
// PAREN_TYPE@24..26
|
// L_ANGLE@23..24 "<"
|
||||||
// L_PAREN@24..25 "("
|
// PAREN_TYPE@24..26
|
||||||
// ERROR@25..26
|
// L_PAREN@24..25 "("
|
||||||
// INT_NUMBER@25..26 "8"
|
// ERROR@25..26
|
||||||
|
// INT_NUMBER@25..26 "8"
|
||||||
// PLUS@26..27 "+"
|
// PLUS@26..27 "+"
|
||||||
// CONST_ARG@27..28
|
// CONST_ARG@27..28
|
||||||
// LITERAL@27..28
|
// LITERAL@27..28
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
|
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
|
||||||
HirWrite, ModuleDef, ModuleDefId, Semantics, sym,
|
HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
|
||||||
};
|
};
|
||||||
use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
|
use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
|
||||||
use ide_db::{FxHashSet, text_edit::TextEdit};
|
use ide_db::{FxHashSet, text_edit::TextEdit};
|
||||||
@ -34,6 +34,7 @@ mod extern_block;
|
|||||||
mod generic_param;
|
mod generic_param;
|
||||||
mod implicit_drop;
|
mod implicit_drop;
|
||||||
mod implicit_static;
|
mod implicit_static;
|
||||||
|
mod implied_dyn_trait;
|
||||||
mod lifetime;
|
mod lifetime;
|
||||||
mod param_name;
|
mod param_name;
|
||||||
mod range_exclusive;
|
mod range_exclusive;
|
||||||
@ -95,16 +96,16 @@ pub(crate) fn inlay_hints(
|
|||||||
return acc;
|
return acc;
|
||||||
};
|
};
|
||||||
let famous_defs = FamousDefs(&sema, scope.krate());
|
let famous_defs = FamousDefs(&sema, scope.krate());
|
||||||
|
let display_target = famous_defs.1.to_display_target(sema.db);
|
||||||
|
|
||||||
let ctx = &mut InlayHintCtx::default();
|
let ctx = &mut InlayHintCtx::default();
|
||||||
let mut hints = |event| {
|
let mut hints = |event| {
|
||||||
if let Some(node) = handle_event(ctx, event) {
|
if let Some(node) = handle_event(ctx, event) {
|
||||||
hints(&mut acc, ctx, &famous_defs, config, file_id, node);
|
hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut preorder = file.preorder();
|
let mut preorder = file.preorder();
|
||||||
while let Some(event) = preorder.next() {
|
while let Some(event) = preorder.next() {
|
||||||
// FIXME: This can miss some hints that require the parent of the range to calculate
|
|
||||||
if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
|
if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
|
||||||
{
|
{
|
||||||
preorder.skip_subtree();
|
preorder.skip_subtree();
|
||||||
@ -144,10 +145,12 @@ pub(crate) fn inlay_hints_resolve(
|
|||||||
let famous_defs = FamousDefs(&sema, scope.krate());
|
let famous_defs = FamousDefs(&sema, scope.krate());
|
||||||
let mut acc = Vec::new();
|
let mut acc = Vec::new();
|
||||||
|
|
||||||
|
let display_target = famous_defs.1.to_display_target(sema.db);
|
||||||
|
|
||||||
let ctx = &mut InlayHintCtx::default();
|
let ctx = &mut InlayHintCtx::default();
|
||||||
let mut hints = |event| {
|
let mut hints = |event| {
|
||||||
if let Some(node) = handle_event(ctx, event) {
|
if let Some(node) = handle_event(ctx, event) {
|
||||||
hints(&mut acc, ctx, &famous_defs, config, file_id, node);
|
hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,17 +205,19 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<S
|
|||||||
fn hints(
|
fn hints(
|
||||||
hints: &mut Vec<InlayHint>,
|
hints: &mut Vec<InlayHint>,
|
||||||
ctx: &mut InlayHintCtx,
|
ctx: &mut InlayHintCtx,
|
||||||
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
file_id: EditionedFileId,
|
||||||
|
display_target: DisplayTarget,
|
||||||
node: SyntaxNode,
|
node: SyntaxNode,
|
||||||
) {
|
) {
|
||||||
let file_id = file_id.editioned_file_id(sema.db);
|
closing_brace::hints(
|
||||||
let Some(krate) = sema.first_crate(file_id.file_id()) else {
|
hints,
|
||||||
return;
|
sema,
|
||||||
};
|
config,
|
||||||
let display_target = krate.to_display_target(sema.db);
|
display_target,
|
||||||
closing_brace::hints(hints, sema, config, file_id, display_target, node.clone());
|
InRealFile { file_id, value: node.clone() },
|
||||||
|
);
|
||||||
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
|
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
|
||||||
generic_param::hints(hints, famous_defs, config, any_has_generic_args);
|
generic_param::hints(hints, famous_defs, config, any_has_generic_args);
|
||||||
}
|
}
|
||||||
@ -231,18 +236,18 @@ fn hints(
|
|||||||
closure_captures::hints(hints, famous_defs, config, it.clone());
|
closure_captures::hints(hints, famous_defs, config, it.clone());
|
||||||
closure_ret::hints(hints, famous_defs, config, display_target, it)
|
closure_ret::hints(hints, famous_defs, config, display_target, it)
|
||||||
},
|
},
|
||||||
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it),
|
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
|
||||||
_ => Some(()),
|
_ => Some(()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::Pat(it) => {
|
ast::Pat(it) => {
|
||||||
binding_mode::hints(hints, famous_defs, config, file_id, &it);
|
binding_mode::hints(hints, famous_defs, config, &it);
|
||||||
match it {
|
match it {
|
||||||
ast::Pat::IdentPat(it) => {
|
ast::Pat::IdentPat(it) => {
|
||||||
bind_pat::hints(hints, famous_defs, config, display_target, &it);
|
bind_pat::hints(hints, famous_defs, config, display_target, &it);
|
||||||
}
|
}
|
||||||
ast::Pat::RangePat(it) => {
|
ast::Pat::RangePat(it) => {
|
||||||
range_exclusive::hints(hints, famous_defs, config, file_id, it);
|
range_exclusive::hints(hints, famous_defs, config, it);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -250,30 +255,38 @@ fn hints(
|
|||||||
},
|
},
|
||||||
ast::Item(it) => match it {
|
ast::Item(it) => match it {
|
||||||
ast::Item::Fn(it) => {
|
ast::Item::Fn(it) => {
|
||||||
implicit_drop::hints(hints, famous_defs, config, file_id, &it);
|
implicit_drop::hints(hints, famous_defs, config, display_target, &it);
|
||||||
if let Some(extern_block) = &ctx.extern_block_parent {
|
if let Some(extern_block) = &ctx.extern_block_parent {
|
||||||
extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block);
|
extern_block::fn_hints(hints, famous_defs, config, &it, extern_block);
|
||||||
}
|
}
|
||||||
lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it)
|
lifetime::fn_hints(hints, ctx, famous_defs, config, it)
|
||||||
},
|
},
|
||||||
ast::Item::Static(it) => {
|
ast::Item::Static(it) => {
|
||||||
if let Some(extern_block) = &ctx.extern_block_parent {
|
if let Some(extern_block) = &ctx.extern_block_parent {
|
||||||
extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block);
|
extern_block::static_hints(hints, famous_defs, config, &it, extern_block);
|
||||||
}
|
}
|
||||||
implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it))
|
implicit_static::hints(hints, famous_defs, config, Either::Left(it))
|
||||||
},
|
},
|
||||||
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
|
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, Either::Right(it)),
|
||||||
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
|
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, it),
|
||||||
ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it),
|
ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, it),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
// FIXME: trait object type elisions
|
// FIXME: trait object type elisions
|
||||||
ast::Type(ty) => match ty {
|
ast::Type(ty) => match ty {
|
||||||
ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, file_id, ptr),
|
ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, ptr),
|
||||||
ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path),
|
ast::Type::PathType(path) => {
|
||||||
|
lifetime::fn_path_hints(hints, ctx, famous_defs, config, &path);
|
||||||
|
implied_dyn_trait::hints(hints, famous_defs, config, Either::Left(path));
|
||||||
|
Some(())
|
||||||
|
},
|
||||||
|
ast::Type::DynTraitType(dyn_) => {
|
||||||
|
implied_dyn_trait::hints(hints, famous_defs, config, Either::Right(dyn_));
|
||||||
|
Some(())
|
||||||
|
},
|
||||||
_ => Some(()),
|
_ => Some(()),
|
||||||
},
|
},
|
||||||
ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, file_id, it),
|
ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, it),
|
||||||
_ => Some(()),
|
_ => Some(()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -438,6 +451,7 @@ pub enum InlayKind {
|
|||||||
Parameter,
|
Parameter,
|
||||||
GenericParameter,
|
GenericParameter,
|
||||||
Type,
|
Type,
|
||||||
|
Dyn,
|
||||||
Drop,
|
Drop,
|
||||||
RangeExclusive,
|
RangeExclusive,
|
||||||
ExternUnsafety,
|
ExternUnsafety,
|
||||||
|
@ -8,7 +8,6 @@ use hir::Mutability;
|
|||||||
use ide_db::famous_defs::FamousDefs;
|
use ide_db::famous_defs::FamousDefs;
|
||||||
|
|
||||||
use ide_db::text_edit::TextEditBuilder;
|
use ide_db::text_edit::TextEditBuilder;
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::ast::{self, AstNode};
|
use syntax::ast::{self, AstNode};
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
|
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
|
||||||
@ -17,7 +16,6 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
pat: &ast::Pat,
|
pat: &ast::Pat,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.binding_mode_hints {
|
if !config.binding_mode_hints {
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
//! Currently this renders the implied `Sized` bound.
|
//! Currently this renders the implied `Sized` bound.
|
||||||
use ide_db::{FileRange, famous_defs::FamousDefs};
|
use ide_db::{FileRange, famous_defs::FamousDefs};
|
||||||
|
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::ast::{self, AstNode, HasTypeBounds};
|
use syntax::ast::{self, AstNode, HasTypeBounds};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -15,7 +14,6 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
params: ast::GenericParamList,
|
params: ast::GenericParamList,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.sized_bound {
|
if !config.sized_bound {
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
//! fn g() {
|
//! fn g() {
|
||||||
//! } /* fn g */
|
//! } /* fn g */
|
||||||
//! ```
|
//! ```
|
||||||
use hir::{DisplayTarget, HirDisplay, Semantics};
|
use hir::{DisplayTarget, HirDisplay, InRealFile, Semantics};
|
||||||
use ide_db::{FileRange, RootDatabase};
|
use ide_db::{FileRange, RootDatabase};
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
SyntaxKind, SyntaxNode, T,
|
SyntaxKind, SyntaxNode, T,
|
||||||
ast::{self, AstNode, HasLoopBody, HasName},
|
ast::{self, AstNode, HasLoopBody, HasName},
|
||||||
@ -21,15 +20,14 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
|
||||||
display_target: DisplayTarget,
|
display_target: DisplayTarget,
|
||||||
original_node: SyntaxNode,
|
InRealFile { file_id, value: node }: InRealFile<SyntaxNode>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let min_lines = config.closing_brace_hints_min_lines?;
|
let min_lines = config.closing_brace_hints_min_lines?;
|
||||||
|
|
||||||
let name = |it: ast::Name| it.syntax().text_range();
|
let name = |it: ast::Name| it.syntax().text_range();
|
||||||
|
|
||||||
let mut node = original_node.clone();
|
let mut node = node.clone();
|
||||||
let mut closing_token;
|
let mut closing_token;
|
||||||
let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
||||||
closing_token = item_list.r_curly_token()?;
|
closing_token = item_list.r_curly_token()?;
|
||||||
@ -44,7 +42,7 @@ pub(super) fn hints(
|
|||||||
let hint_text = match trait_ {
|
let hint_text = match trait_ {
|
||||||
Some(tr) => format!(
|
Some(tr) => format!(
|
||||||
"impl {} for {}",
|
"impl {} for {}",
|
||||||
tr.name(sema.db).display(sema.db, file_id.edition()),
|
tr.name(sema.db).display(sema.db, display_target.edition),
|
||||||
ty.display_truncated(sema.db, config.max_length, display_target,
|
ty.display_truncated(sema.db, config.max_length, display_target,
|
||||||
)),
|
)),
|
||||||
None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, display_target)),
|
None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, display_target)),
|
||||||
@ -142,7 +140,8 @@ pub(super) fn hints(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let linked_location = name_range.map(|range| FileRange { file_id: file_id.into(), range });
|
let linked_location =
|
||||||
|
name_range.map(|range| FileRange { file_id: file_id.file_id(sema.db), range });
|
||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: closing_token.text_range(),
|
range: closing_token.text_range(),
|
||||||
kind: InlayKind::ClosingBrace,
|
kind: InlayKind::ClosingBrace,
|
||||||
@ -151,7 +150,7 @@ pub(super) fn hints(
|
|||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: true,
|
pad_left: true,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
resolve_parent: Some(original_node.text_range()),
|
resolve_parent: Some(node.text_range()),
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::text_edit::TextEdit;
|
use ide_db::text_edit::TextEdit;
|
||||||
use ide_db::{RootDatabase, famous_defs::FamousDefs};
|
use ide_db::{RootDatabase, famous_defs::FamousDefs};
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::ast::{self, AstNode, HasName};
|
use syntax::ast::{self, AstNode, HasName};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -19,7 +18,6 @@ pub(super) fn enum_hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_: EditionedFileId,
|
|
||||||
enum_: ast::Enum,
|
enum_: ast::Enum,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if let DiscriminantHints::Never = config.discriminant_hints {
|
if let DiscriminantHints::Never = config.discriminant_hints {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Extern block hints
|
//! Extern block hints
|
||||||
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
|
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{AstNode, SyntaxToken, ast};
|
use syntax::{AstNode, SyntaxToken, ast};
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintsConfig};
|
use crate::{InlayHint, InlayHintsConfig};
|
||||||
@ -9,7 +8,6 @@ pub(super) fn extern_block_hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
extern_block: ast::ExternBlock,
|
extern_block: ast::ExternBlock,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if extern_block.unsafe_token().is_some() {
|
if extern_block.unsafe_token().is_some() {
|
||||||
@ -36,7 +34,6 @@ pub(super) fn fn_hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
fn_: &ast::Fn,
|
fn_: &ast::Fn,
|
||||||
extern_block: &ast::ExternBlock,
|
extern_block: &ast::ExternBlock,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
@ -55,7 +52,6 @@ pub(super) fn static_hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
static_: &ast::Static,
|
static_: &ast::Static,
|
||||||
extern_block: &ast::ExternBlock,
|
extern_block: &ast::ExternBlock,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
@ -12,7 +12,6 @@ use hir::{
|
|||||||
};
|
};
|
||||||
use ide_db::{FileRange, famous_defs::FamousDefs};
|
use ide_db::{FileRange, famous_defs::FamousDefs};
|
||||||
|
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ToSmolStr,
|
ToSmolStr,
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
@ -25,7 +24,7 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
display_target: hir::DisplayTarget,
|
||||||
node: &ast::Fn,
|
node: &ast::Fn,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if !config.implicit_drop_hints {
|
if !config.implicit_drop_hints {
|
||||||
@ -94,7 +93,7 @@ pub(super) fn hints(
|
|||||||
MirSpan::Unknown => continue,
|
MirSpan::Unknown => continue,
|
||||||
};
|
};
|
||||||
let binding = &hir.bindings[binding_idx];
|
let binding = &hir.bindings[binding_idx];
|
||||||
let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
|
let name = binding.name.display_no_db(display_target.edition).to_smolstr();
|
||||||
if name.starts_with("<ra@") {
|
if name.starts_with("<ra@") {
|
||||||
continue; // Ignore desugared variables
|
continue; // Ignore desugared variables
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
use either::Either;
|
use either::Either;
|
||||||
use ide_db::famous_defs::FamousDefs;
|
use ide_db::famous_defs::FamousDefs;
|
||||||
use ide_db::text_edit::TextEdit;
|
use ide_db::text_edit::TextEdit;
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
@ -17,7 +16,6 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
statik_or_const: Either<ast::Static, ast::Const>,
|
statik_or_const: Either<ast::Static, ast::Const>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints != LifetimeElisionHints::Always {
|
if config.lifetime_elision_hints != LifetimeElisionHints::Always {
|
||||||
|
133
crates/ide/src/inlay_hints/implied_dyn_trait.rs
Normal file
133
crates/ide/src/inlay_hints/implied_dyn_trait.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
//! Implementation of trait bound hints.
|
||||||
|
//!
|
||||||
|
//! Currently this renders the implied `Sized` bound.
|
||||||
|
use either::Either;
|
||||||
|
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
|
||||||
|
|
||||||
|
use syntax::ast::{self, AstNode};
|
||||||
|
|
||||||
|
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
|
||||||
|
|
||||||
|
pub(super) fn hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
path: Either<ast::PathType, ast::DynTraitType>,
|
||||||
|
) -> Option<()> {
|
||||||
|
let parent = path.syntax().parent()?;
|
||||||
|
let range = match path {
|
||||||
|
Either::Left(path) => {
|
||||||
|
let paren =
|
||||||
|
parent.ancestors().take_while(|it| ast::ParenType::can_cast(it.kind())).last();
|
||||||
|
let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent);
|
||||||
|
if ast::TypeBound::can_cast(parent.kind())
|
||||||
|
|| ast::TypeAnchor::can_cast(parent.kind())
|
||||||
|
|| ast::Impl::cast(parent)
|
||||||
|
.and_then(|it| it.trait_())
|
||||||
|
.is_some_and(|it| it.syntax() == path.syntax())
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
sema.resolve_trait(&path.path()?)?;
|
||||||
|
paren.map_or_else(|| path.syntax().text_range(), |it| it.text_range())
|
||||||
|
}
|
||||||
|
Either::Right(dyn_) => {
|
||||||
|
if dyn_.dyn_token().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_.syntax().text_range()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
acc.push(InlayHint {
|
||||||
|
range,
|
||||||
|
kind: InlayKind::Dyn,
|
||||||
|
label: InlayHintLabel::simple("dyn", None, None),
|
||||||
|
text_edit: Some(
|
||||||
|
config.lazy_text_edit(|| TextEdit::insert(range.start(), "dyn ".to_owned())),
|
||||||
|
),
|
||||||
|
position: InlayHintPosition::Before,
|
||||||
|
pad_left: false,
|
||||||
|
pad_right: true,
|
||||||
|
resolve_parent: Some(range),
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use expect_test::expect;
|
||||||
|
|
||||||
|
use crate::inlay_hints::InlayHintsConfig;
|
||||||
|
|
||||||
|
use crate::inlay_hints::tests::{DISABLED_CONFIG, check_edit, check_with_config};
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
|
||||||
|
check_with_config(InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, ra_fixture);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn path_works() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct S {}
|
||||||
|
trait T {}
|
||||||
|
fn foo(_: T, _: dyn T, _: S) {}
|
||||||
|
// ^ dyn
|
||||||
|
fn foo(_: &T, _: for<'a> T) {}
|
||||||
|
// ^ dyn
|
||||||
|
// ^ dyn
|
||||||
|
impl T {}
|
||||||
|
// ^ dyn
|
||||||
|
impl T for (T) {}
|
||||||
|
// ^^^ dyn
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_dyn_bounds() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait T {}
|
||||||
|
fn foo(
|
||||||
|
_: T + T,
|
||||||
|
// ^^^^^ dyn
|
||||||
|
_: T + 'a,
|
||||||
|
// ^^^^^^ dyn
|
||||||
|
_: 'a + T,
|
||||||
|
// ^^^^^^ dyn
|
||||||
|
_: &(T + T)
|
||||||
|
// ^^^^^ dyn
|
||||||
|
_: &mut (T + T)
|
||||||
|
// ^^^^^ dyn
|
||||||
|
_: *mut (T),
|
||||||
|
// ^^^ dyn
|
||||||
|
) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn edit() {
|
||||||
|
check_edit(
|
||||||
|
DISABLED_CONFIG,
|
||||||
|
r#"
|
||||||
|
trait T {}
|
||||||
|
fn foo(
|
||||||
|
_: &mut T
|
||||||
|
) {}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
trait T {}
|
||||||
|
fn foo(
|
||||||
|
_: &mut dyn T
|
||||||
|
) {}
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ use std::iter;
|
|||||||
|
|
||||||
use ide_db::{FxHashMap, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty};
|
use ide_db::{FxHashMap, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{SmolStr, format_smolstr};
|
use syntax::{SmolStr, format_smolstr};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
SyntaxKind, SyntaxToken,
|
SyntaxKind, SyntaxToken,
|
||||||
@ -23,7 +22,6 @@ pub(super) fn fn_hints(
|
|||||||
ctx: &mut InlayHintCtx,
|
ctx: &mut InlayHintCtx,
|
||||||
fd: &FamousDefs<'_, '_>,
|
fd: &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
|
||||||
func: ast::Fn,
|
func: ast::Fn,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
||||||
@ -40,7 +38,6 @@ pub(super) fn fn_hints(
|
|||||||
ctx,
|
ctx,
|
||||||
fd,
|
fd,
|
||||||
config,
|
config,
|
||||||
file_id,
|
|
||||||
param_list.params().filter_map(|it| {
|
param_list.params().filter_map(|it| {
|
||||||
Some((
|
Some((
|
||||||
it.pat().and_then(|it| match it {
|
it.pat().and_then(|it| match it {
|
||||||
@ -74,7 +71,6 @@ pub(super) fn fn_ptr_hints(
|
|||||||
ctx: &mut InlayHintCtx,
|
ctx: &mut InlayHintCtx,
|
||||||
fd: &FamousDefs<'_, '_>,
|
fd: &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
|
||||||
func: ast::FnPtrType,
|
func: ast::FnPtrType,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
||||||
@ -97,7 +93,6 @@ pub(super) fn fn_ptr_hints(
|
|||||||
ctx,
|
ctx,
|
||||||
fd,
|
fd,
|
||||||
config,
|
config,
|
||||||
file_id,
|
|
||||||
param_list.params().filter_map(|it| {
|
param_list.params().filter_map(|it| {
|
||||||
Some((
|
Some((
|
||||||
it.pat().and_then(|it| match it {
|
it.pat().and_then(|it| match it {
|
||||||
@ -140,8 +135,7 @@ pub(super) fn fn_path_hints(
|
|||||||
ctx: &mut InlayHintCtx,
|
ctx: &mut InlayHintCtx,
|
||||||
fd: &FamousDefs<'_, '_>,
|
fd: &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
file_id: EditionedFileId,
|
func: &ast::PathType,
|
||||||
func: ast::PathType,
|
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
|
||||||
return None;
|
return None;
|
||||||
@ -163,7 +157,6 @@ pub(super) fn fn_path_hints(
|
|||||||
ctx,
|
ctx,
|
||||||
fd,
|
fd,
|
||||||
config,
|
config,
|
||||||
file_id,
|
|
||||||
param_list.type_args().filter_map(|it| Some((None, it.ty()?))),
|
param_list.type_args().filter_map(|it| Some((None, it.ty()?))),
|
||||||
generic_param_list,
|
generic_param_list,
|
||||||
ret_type,
|
ret_type,
|
||||||
@ -202,7 +195,6 @@ fn hints_(
|
|||||||
ctx: &mut InlayHintCtx,
|
ctx: &mut InlayHintCtx,
|
||||||
FamousDefs(_, _): &FamousDefs<'_, '_>,
|
FamousDefs(_, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
|
params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
|
||||||
generic_param_list: Option<ast::GenericParamList>,
|
generic_param_list: Option<ast::GenericParamList>,
|
||||||
ret_type: Option<ast::RetType>,
|
ret_type: Option<ast::RetType>,
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
//! if let ../* < */100 = 50 {}
|
//! if let ../* < */100 = 50 {}
|
||||||
//! ```
|
//! ```
|
||||||
use ide_db::famous_defs::FamousDefs;
|
use ide_db::famous_defs::FamousDefs;
|
||||||
use span::EditionedFileId;
|
|
||||||
use syntax::{SyntaxToken, T, ast};
|
use syntax::{SyntaxToken, T, ast};
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintsConfig};
|
use crate::{InlayHint, InlayHintsConfig};
|
||||||
@ -13,7 +12,6 @@ pub(super) fn hints(
|
|||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
|
||||||
range: impl ast::RangeItem,
|
range: impl ast::RangeItem,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
(config.range_exclusive_hints && range.end().is_some())
|
(config.range_exclusive_hints && range.end().is_some())
|
||||||
|
@ -89,7 +89,9 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
|
|||||||
// test qual_paths
|
// test qual_paths
|
||||||
// type X = <A as B>::Output;
|
// type X = <A as B>::Output;
|
||||||
// fn foo() { <usize as Default>::default(); }
|
// fn foo() { <usize as Default>::default(); }
|
||||||
if first && p.eat(T![<]) {
|
if first && p.at(T![<]) {
|
||||||
|
let m = p.start();
|
||||||
|
p.bump(T![<]);
|
||||||
// test_err angled_path_without_qual
|
// test_err angled_path_without_qual
|
||||||
// type X = <()>;
|
// type X = <()>;
|
||||||
// type Y = <A as B>;
|
// type Y = <A as B>;
|
||||||
@ -102,6 +104,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expect(T![>]);
|
p.expect(T![>]);
|
||||||
|
m.complete(p, TYPE_ANCHOR);
|
||||||
if !p.at(T![::]) {
|
if !p.at(T![::]) {
|
||||||
p.error("expected `::`");
|
p.error("expected `::`");
|
||||||
}
|
}
|
||||||
|
@ -291,6 +291,7 @@ pub enum SyntaxKind {
|
|||||||
TUPLE_STRUCT_PAT,
|
TUPLE_STRUCT_PAT,
|
||||||
TUPLE_TYPE,
|
TUPLE_TYPE,
|
||||||
TYPE_ALIAS,
|
TYPE_ALIAS,
|
||||||
|
TYPE_ANCHOR,
|
||||||
TYPE_ARG,
|
TYPE_ARG,
|
||||||
TYPE_BOUND,
|
TYPE_BOUND,
|
||||||
TYPE_BOUND_LIST,
|
TYPE_BOUND_LIST,
|
||||||
@ -463,6 +464,7 @@ impl SyntaxKind {
|
|||||||
| TUPLE_STRUCT_PAT
|
| TUPLE_STRUCT_PAT
|
||||||
| TUPLE_TYPE
|
| TUPLE_TYPE
|
||||||
| TYPE_ALIAS
|
| TYPE_ALIAS
|
||||||
|
| TYPE_ANCHOR
|
||||||
| TYPE_ARG
|
| TYPE_ARG
|
||||||
| TYPE_BOUND
|
| TYPE_BOUND
|
||||||
| TYPE_BOUND_LIST
|
| TYPE_BOUND_LIST
|
||||||
|
@ -10,11 +10,12 @@ SOURCE_FILE
|
|||||||
PATH_TYPE
|
PATH_TYPE
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
TUPLE_TYPE
|
L_ANGLE "<"
|
||||||
L_PAREN "("
|
TUPLE_TYPE
|
||||||
R_PAREN ")"
|
L_PAREN "("
|
||||||
R_ANGLE ">"
|
R_PAREN ")"
|
||||||
|
R_ANGLE ">"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
TYPE_ALIAS
|
TYPE_ALIAS
|
||||||
@ -28,21 +29,22 @@ SOURCE_FILE
|
|||||||
PATH_TYPE
|
PATH_TYPE
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "A"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "A"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "B"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "B"
|
||||||
|
R_ANGLE ">"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
error 13: expected `::`
|
error 13: expected `::`
|
||||||
|
@ -88,13 +88,14 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Foo"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Foo"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
@ -119,21 +120,22 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Foo"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "Foo"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Trait"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Trait"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -11,21 +11,22 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "A"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "A"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "B"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "B"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
@ -51,21 +52,22 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "usize"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "usize"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Default"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Default"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -19,10 +19,11 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
INFER_TYPE
|
L_ANGLE "<"
|
||||||
UNDERSCORE "_"
|
INFER_TYPE
|
||||||
R_ANGLE ">"
|
UNDERSCORE "_"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -84,21 +84,22 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "T"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "T"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Iterator"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Iterator"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -45,21 +45,22 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "S"
|
NAME_REF
|
||||||
WHITESPACE " "
|
IDENT "S"
|
||||||
AS_KW "as"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
AS_KW "as"
|
||||||
PATH_TYPE
|
WHITESPACE " "
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Iterator"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Iterator"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -107,13 +107,14 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
PATH_TYPE
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "Foo"
|
NAME_REF
|
||||||
R_ANGLE ">"
|
IDENT "Foo"
|
||||||
|
R_ANGLE ">"
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -288,26 +288,27 @@ SOURCE_FILE
|
|||||||
PATH
|
PATH
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
TYPE_ANCHOR
|
||||||
REF_TYPE
|
L_ANGLE "<"
|
||||||
AMP "&"
|
REF_TYPE
|
||||||
LIFETIME
|
AMP "&"
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME
|
||||||
|
LIFETIME_IDENT "'a"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "T"
|
||||||
|
WHITESPACE " "
|
||||||
|
AS_KW "as"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
PATH_TYPE
|
PATH_TYPE
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "T"
|
IDENT "Baz"
|
||||||
WHITESPACE " "
|
R_ANGLE ">"
|
||||||
AS_KW "as"
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_TYPE
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Baz"
|
|
||||||
R_ANGLE ">"
|
|
||||||
COLON2 "::"
|
COLON2 "::"
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -39,7 +39,10 @@ PathSegment =
|
|||||||
| NameRef GenericArgList?
|
| NameRef GenericArgList?
|
||||||
| NameRef ParenthesizedArgList RetType?
|
| NameRef ParenthesizedArgList RetType?
|
||||||
| NameRef ReturnTypeSyntax
|
| NameRef ReturnTypeSyntax
|
||||||
| '<' Type ('as' PathType)? '>'
|
| TypeAnchor
|
||||||
|
|
||||||
|
TypeAnchor =
|
||||||
|
'<' Type ('as' PathType)? '>'
|
||||||
|
|
||||||
ReturnTypeSyntax =
|
ReturnTypeSyntax =
|
||||||
'(' '..' ')'
|
'(' '..' ')'
|
||||||
@ -98,7 +101,7 @@ WhereClause =
|
|||||||
'where' predicates:(WherePred (',' WherePred)* ','?)
|
'where' predicates:(WherePred (',' WherePred)* ','?)
|
||||||
|
|
||||||
WherePred =
|
WherePred =
|
||||||
('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList?
|
('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList?
|
||||||
|
|
||||||
|
|
||||||
//*************************//
|
//*************************//
|
||||||
|
@ -1232,21 +1232,13 @@ impl PathSegment {
|
|||||||
support::child(&self.syntax)
|
support::child(&self.syntax)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
|
|
||||||
#[inline]
|
|
||||||
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
|
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) }
|
pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
|
pub fn type_anchor(&self) -> Option<TypeAnchor> { support::child(&self.syntax) }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
|
pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
|
||||||
#[inline]
|
|
||||||
pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
|
|
||||||
#[inline]
|
|
||||||
pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
|
|
||||||
#[inline]
|
|
||||||
pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
|
|
||||||
}
|
}
|
||||||
pub struct PathType {
|
pub struct PathType {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
@ -1739,6 +1731,21 @@ impl TypeAlias {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
|
pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
|
||||||
}
|
}
|
||||||
|
pub struct TypeAnchor {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl TypeAnchor {
|
||||||
|
#[inline]
|
||||||
|
pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
|
||||||
|
}
|
||||||
pub struct TypeArg {
|
pub struct TypeArg {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
@ -7108,6 +7115,42 @@ impl fmt::Debug for TypeAlias {
|
|||||||
f.debug_struct("TypeAlias").field("syntax", &self.syntax).finish()
|
f.debug_struct("TypeAlias").field("syntax", &self.syntax).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl AstNode for TypeAnchor {
|
||||||
|
#[inline]
|
||||||
|
fn kind() -> SyntaxKind
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
TYPE_ANCHOR
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl hash::Hash for TypeAnchor {
|
||||||
|
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
|
||||||
|
}
|
||||||
|
impl Eq for TypeAnchor {}
|
||||||
|
impl PartialEq for TypeAnchor {
|
||||||
|
fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
|
||||||
|
}
|
||||||
|
impl Clone for TypeAnchor {
|
||||||
|
fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
|
||||||
|
}
|
||||||
|
impl fmt::Debug for TypeAnchor {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("TypeAnchor").field("syntax", &self.syntax).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl AstNode for TypeArg {
|
impl AstNode for TypeArg {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn kind() -> SyntaxKind
|
fn kind() -> SyntaxKind
|
||||||
@ -10624,6 +10667,11 @@ impl std::fmt::Display for TypeAlias {
|
|||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for TypeAnchor {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for TypeArg {
|
impl std::fmt::Display for TypeArg {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -276,18 +276,15 @@ impl ast::PathSegment {
|
|||||||
_ => PathSegmentKind::Name(name_ref),
|
_ => PathSegmentKind::Name(name_ref),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.syntax().first_child_or_token()?.kind() {
|
let anchor = self.type_anchor()?;
|
||||||
T![<] => {
|
// FIXME: Move this over to `ast::TypeAnchor`
|
||||||
// <T> or <T as Trait>
|
// <T> or <T as Trait>
|
||||||
// T is any TypeRef, Trait has to be a PathType
|
// T is any TypeRef, Trait has to be a PathType
|
||||||
let mut type_refs =
|
let mut type_refs =
|
||||||
self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
|
anchor.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
|
||||||
let type_ref = type_refs.next().and_then(ast::Type::cast);
|
let type_ref = type_refs.next().and_then(ast::Type::cast);
|
||||||
let trait_ref = type_refs.next().and_then(ast::PathType::cast);
|
let trait_ref = type_refs.next().and_then(ast::PathType::cast);
|
||||||
PathSegmentKind::Type { type_ref, trait_ref }
|
PathSegmentKind::Type { type_ref, trait_ref }
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
@ -473,7 +470,7 @@ impl ast::Impl {
|
|||||||
// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
|
// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
|
||||||
impl ast::PathSegment {
|
impl ast::PathSegment {
|
||||||
pub fn qualifying_trait(&self) -> Option<ast::PathType> {
|
pub fn qualifying_trait(&self) -> Option<ast::PathType> {
|
||||||
let mut path_types = support::children(self.syntax());
|
let mut path_types = support::children(self.type_anchor()?.syntax());
|
||||||
let first = path_types.next()?;
|
let first = path_types.next()?;
|
||||||
path_types.next().or(Some(first))
|
path_types.next().or(Some(first))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user