mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
fix: Fix incorrect parsing of use bounds
Also lower them a bit more
This commit is contained in:
parent
17055aaca9
commit
95298a2e61
11 changed files with 184 additions and 25 deletions
|
@ -157,9 +157,19 @@ pub enum TypeBound {
|
|||
Path(Path, TraitBoundModifier),
|
||||
ForLifetime(Box<[Name]>, Path),
|
||||
Lifetime(LifetimeRef),
|
||||
Use(Box<[UseArgRef]>),
|
||||
Error,
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const _: [(); 56] = [(); ::std::mem::size_of::<TypeBound>()];
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum UseArgRef {
|
||||
Name(Name),
|
||||
Lifetime(LifetimeRef),
|
||||
}
|
||||
|
||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||
/// modifier is `Maybe`.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
@ -295,7 +305,7 @@ impl TypeRef {
|
|||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +338,7 @@ impl TypeRef {
|
|||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
go_path(path, f)
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +390,16 @@ impl TypeBound {
|
|||
None => TypeBound::Error,
|
||||
}
|
||||
}
|
||||
ast::TypeBoundKind::Use(_) => TypeBound::Error,
|
||||
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
|
||||
gal.use_bound_generic_args()
|
||||
.map(|p| match p {
|
||||
ast::UseBoundGenericArg::Lifetime(l) => {
|
||||
UseArgRef::Lifetime(LifetimeRef::new(&l))
|
||||
}
|
||||
ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
ast::TypeBoundKind::Lifetime(lifetime) => {
|
||||
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
|
||||
}
|
||||
|
@ -391,7 +410,7 @@ impl TypeBound {
|
|||
match self {
|
||||
TypeBound::Path(p, m) => Some((p, m)),
|
||||
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => None,
|
||||
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
//! Display and pretty printing routines.
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
mem,
|
||||
};
|
||||
|
||||
use hir_expand::mod_path::PathKind;
|
||||
use intern::Interned;
|
||||
|
@ -11,7 +14,7 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
lang_item::LangItemTarget,
|
||||
path::{GenericArg, GenericArgs, Path},
|
||||
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
|
||||
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
|
||||
};
|
||||
|
||||
pub(crate) fn print_path(
|
||||
|
@ -273,6 +276,22 @@ pub(crate) fn print_type_bounds(
|
|||
print_path(db, path, buf, edition)?;
|
||||
}
|
||||
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
|
||||
TypeBound::Use(args) => {
|
||||
write!(buf, "use<")?;
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
if !mem::take(&mut first) {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
match arg {
|
||||
UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
|
||||
UseArgRef::Lifetime(it) => {
|
||||
write!(buf, "{}", it.name.display(db.upcast(), edition))?
|
||||
}
|
||||
}
|
||||
}
|
||||
write!(buf, ">")?
|
||||
}
|
||||
TypeBound::Error => write!(buf, "{{unknown}}")?,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use hir_def::{
|
|||
lang_item::{LangItem, LangItemTarget},
|
||||
nameres::DefMap,
|
||||
path::{Path, PathKind},
|
||||
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
|
||||
type_ref::{TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
|
||||
visibility::Visibility,
|
||||
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
|
||||
ModuleId, TraitId,
|
||||
|
@ -2025,6 +2025,19 @@ impl HirDisplay for TypeBound {
|
|||
)?;
|
||||
path.hir_fmt(f)
|
||||
}
|
||||
TypeBound::Use(args) => {
|
||||
let edition = f.edition();
|
||||
write!(
|
||||
f,
|
||||
"use<{}> ",
|
||||
args.iter()
|
||||
.map(|it| match it {
|
||||
UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
|
||||
UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
|
||||
})
|
||||
.format(", ")
|
||||
)
|
||||
}
|
||||
TypeBound::Error => write!(f, "{{error}}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1067,7 +1067,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
lifetime,
|
||||
})))
|
||||
}
|
||||
TypeBound::Error => None,
|
||||
TypeBound::Use(_) | TypeBound::Error => None,
|
||||
};
|
||||
clause.into_iter().chain(
|
||||
trait_ref
|
||||
|
@ -1087,6 +1087,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
path.segments().last()
|
||||
}
|
||||
TypeBound::Path(_, TraitBoundModifier::Maybe)
|
||||
| TypeBound::Use(_)
|
||||
| TypeBound::Error
|
||||
| TypeBound::Lifetime(_) => None,
|
||||
};
|
||||
|
@ -1571,7 +1572,7 @@ pub(crate) fn generic_predicates_for_param_query(
|
|||
})
|
||||
})
|
||||
}
|
||||
TypeBound::Lifetime(_) | TypeBound::Error => false,
|
||||
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
|
||||
}
|
||||
}
|
||||
WherePredicate::Lifetime { .. } => false,
|
||||
|
|
|
@ -144,10 +144,31 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
|
|||
LIFETIME_IDENT => lifetime(p),
|
||||
T![for] => types::for_type(p, false),
|
||||
// test precise_capturing
|
||||
// fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
|
||||
// fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
|
||||
T![use] if p.nth_at(1, T![<]) => {
|
||||
p.bump_any();
|
||||
generic_param_list(p)
|
||||
let m = p.start();
|
||||
delimited(
|
||||
p,
|
||||
T![<],
|
||||
T![>],
|
||||
T![,],
|
||||
|| "expected identifier or lifetime".into(),
|
||||
TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]),
|
||||
|p| {
|
||||
if p.at(T![Self]) {
|
||||
let m = p.start();
|
||||
p.bump(T![Self]);
|
||||
m.complete(p, NAME_REF);
|
||||
} else if p.at(LIFETIME_IDENT) {
|
||||
lifetime(p);
|
||||
} else {
|
||||
name_ref(p);
|
||||
}
|
||||
true
|
||||
},
|
||||
);
|
||||
m.complete(p, USE_BOUND_GENERIC_ARGS);
|
||||
}
|
||||
T![?] if p.nth_at(1, T![for]) => {
|
||||
// test question_for_type_trait_bound
|
||||
|
|
|
@ -312,6 +312,8 @@ pub enum SyntaxKind {
|
|||
UNDERSCORE_EXPR,
|
||||
UNION,
|
||||
USE,
|
||||
USE_BOUND_GENERIC_ARG,
|
||||
USE_BOUND_GENERIC_ARGS,
|
||||
USE_TREE,
|
||||
USE_TREE_LIST,
|
||||
VARIANT,
|
||||
|
|
|
@ -50,16 +50,18 @@ SOURCE_FILE
|
|||
WHITESPACE " "
|
||||
TYPE_BOUND
|
||||
USE_KW "use"
|
||||
GENERIC_PARAM_LIST
|
||||
USE_BOUND_GENERIC_ARGS
|
||||
L_ANGLE "<"
|
||||
LIFETIME_PARAM
|
||||
LIFETIME
|
||||
LIFETIME_IDENT "'b"
|
||||
LIFETIME
|
||||
LIFETIME_IDENT "'b"
|
||||
COMMA ","
|
||||
WHITESPACE " "
|
||||
TYPE_PARAM
|
||||
NAME
|
||||
IDENT "T"
|
||||
NAME_REF
|
||||
IDENT "T"
|
||||
COMMA ","
|
||||
WHITESPACE " "
|
||||
NAME_REF
|
||||
SELF_TYPE_KW "Self"
|
||||
R_ANGLE ">"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
|
|
|
@ -1 +1 @@
|
|||
fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
|
||||
fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
|
||||
|
|
|
@ -657,7 +657,14 @@ TypeBoundList =
|
|||
TypeBound =
|
||||
Lifetime
|
||||
| ('~' 'const' | 'const')? 'async'? '?'? Type
|
||||
| 'use' GenericParamList
|
||||
| 'use' UseBoundGenericArgs
|
||||
|
||||
UseBoundGenericArgs =
|
||||
'<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
|
||||
|
||||
UseBoundGenericArg =
|
||||
Lifetime
|
||||
| NameRef
|
||||
|
||||
//************************//
|
||||
// Patterns //
|
||||
|
|
|
@ -1993,13 +1993,15 @@ pub struct TypeBound {
|
|||
pub(crate) syntax: SyntaxNode,
|
||||
}
|
||||
impl TypeBound {
|
||||
#[inline]
|
||||
pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
|
||||
#[inline]
|
||||
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
|
||||
#[inline]
|
||||
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
|
||||
#[inline]
|
||||
pub fn use_bound_generic_args(&self) -> Option<UseBoundGenericArgs> {
|
||||
support::child(&self.syntax)
|
||||
}
|
||||
#[inline]
|
||||
pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
|
||||
#[inline]
|
||||
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
|
||||
|
@ -2076,6 +2078,21 @@ impl Use {
|
|||
pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct UseBoundGenericArgs {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
}
|
||||
impl UseBoundGenericArgs {
|
||||
#[inline]
|
||||
pub fn use_bound_generic_args(&self) -> AstChildren<UseBoundGenericArg> {
|
||||
support::children(&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![>]) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct UseTree {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
|
@ -2402,6 +2419,12 @@ pub enum Type {
|
|||
TupleType(TupleType),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum UseBoundGenericArg {
|
||||
Lifetime(Lifetime),
|
||||
NameRef(NameRef),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct AnyHasArgList {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
|
@ -4435,6 +4458,20 @@ impl AstNode for Use {
|
|||
#[inline]
|
||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||
}
|
||||
impl AstNode for UseBoundGenericArgs {
|
||||
#[inline]
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
|
||||
#[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 AstNode for UseTree {
|
||||
#[inline]
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
|
||||
|
@ -5560,6 +5597,34 @@ impl AstNode for Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<Lifetime> for UseBoundGenericArg {
|
||||
#[inline]
|
||||
fn from(node: Lifetime) -> UseBoundGenericArg { UseBoundGenericArg::Lifetime(node) }
|
||||
}
|
||||
impl From<NameRef> for UseBoundGenericArg {
|
||||
#[inline]
|
||||
fn from(node: NameRef) -> UseBoundGenericArg { UseBoundGenericArg::NameRef(node) }
|
||||
}
|
||||
impl AstNode for UseBoundGenericArg {
|
||||
#[inline]
|
||||
fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, LIFETIME | NAME_REF) }
|
||||
#[inline]
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
let res = match syntax.kind() {
|
||||
LIFETIME => UseBoundGenericArg::Lifetime(Lifetime { syntax }),
|
||||
NAME_REF => UseBoundGenericArg::NameRef(NameRef { syntax }),
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
#[inline]
|
||||
fn syntax(&self) -> &SyntaxNode {
|
||||
match self {
|
||||
UseBoundGenericArg::Lifetime(it) => &it.syntax,
|
||||
UseBoundGenericArg::NameRef(it) => &it.syntax,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AnyHasArgList {
|
||||
#[inline]
|
||||
pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
|
||||
|
@ -6570,6 +6635,11 @@ impl std::fmt::Display for Type {
|
|||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for UseBoundGenericArg {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Abi {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
|
@ -7275,6 +7345,11 @@ impl std::fmt::Display for Use {
|
|||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for UseBoundGenericArgs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for UseTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
|
|
|
@ -795,7 +795,7 @@ pub enum TypeBoundKind {
|
|||
/// for<'a> ...
|
||||
ForType(ast::ForType),
|
||||
/// use
|
||||
Use(ast::GenericParamList),
|
||||
Use(ast::UseBoundGenericArgs),
|
||||
/// 'a
|
||||
Lifetime(ast::Lifetime),
|
||||
}
|
||||
|
@ -806,8 +806,8 @@ impl ast::TypeBound {
|
|||
TypeBoundKind::PathType(path_type)
|
||||
} else if let Some(for_type) = support::children(self.syntax()).next() {
|
||||
TypeBoundKind::ForType(for_type)
|
||||
} else if let Some(generic_param_list) = self.generic_param_list() {
|
||||
TypeBoundKind::Use(generic_param_list)
|
||||
} else if let Some(args) = self.use_bound_generic_args() {
|
||||
TypeBoundKind::Use(args)
|
||||
} else if let Some(lifetime) = self.lifetime() {
|
||||
TypeBoundKind::Lifetime(lifetime)
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue