fix: Fix incorrect parsing of use bounds

Also lower them a bit more
This commit is contained in:
Lukas Wirth 2024-10-22 12:09:06 +02:00
parent 17055aaca9
commit 95298a2e61
11 changed files with 184 additions and 25 deletions

View file

@ -157,9 +157,19 @@ pub enum TypeBound {
Path(Path, TraitBoundModifier), Path(Path, TraitBoundModifier),
ForLifetime(Box<[Name]>, Path), ForLifetime(Box<[Name]>, Path),
Lifetime(LifetimeRef), Lifetime(LifetimeRef),
Use(Box<[UseArgRef]>),
Error, 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 /// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. /// modifier is `Maybe`.
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -295,7 +305,7 @@ impl TypeRef {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f) 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) => { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f) go_path(path, f)
} }
TypeBound::Lifetime(_) | TypeBound::Error => (), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
} }
} }
} }
@ -380,7 +390,16 @@ impl TypeBound {
None => TypeBound::Error, 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) => { ast::TypeBoundKind::Lifetime(lifetime) => {
TypeBound::Lifetime(LifetimeRef::new(&lifetime)) TypeBound::Lifetime(LifetimeRef::new(&lifetime))
} }
@ -391,7 +410,7 @@ impl TypeBound {
match self { match self {
TypeBound::Path(p, m) => Some((p, m)), TypeBound::Path(p, m) => Some((p, m)),
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
TypeBound::Lifetime(_) | TypeBound::Error => None, TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
} }
} }
} }

View file

@ -1,6 +1,9 @@
//! Display and pretty printing routines. //! Display and pretty printing routines.
use std::fmt::{self, Write}; use std::{
fmt::{self, Write},
mem,
};
use hir_expand::mod_path::PathKind; use hir_expand::mod_path::PathKind;
use intern::Interned; use intern::Interned;
@ -11,7 +14,7 @@ use crate::{
db::DefDatabase, db::DefDatabase,
lang_item::LangItemTarget, lang_item::LangItemTarget,
path::{GenericArg, GenericArgs, Path}, path::{GenericArg, GenericArgs, Path},
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
}; };
pub(crate) fn print_path( pub(crate) fn print_path(
@ -273,6 +276,22 @@ pub(crate) fn print_type_bounds(
print_path(db, path, buf, edition)?; print_path(db, path, buf, edition)?;
} }
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), 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}}")?, TypeBound::Error => write!(buf, "{{unknown}}")?,
} }
} }

View file

@ -19,7 +19,7 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
nameres::DefMap, nameres::DefMap,
path::{Path, PathKind}, path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef}, type_ref::{TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
visibility::Visibility, visibility::Visibility,
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
ModuleId, TraitId, ModuleId, TraitId,
@ -2025,6 +2025,19 @@ impl HirDisplay for TypeBound {
)?; )?;
path.hir_fmt(f) 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}}"), TypeBound::Error => write!(f, "{{error}}"),
} }
} }

View file

@ -1067,7 +1067,7 @@ impl<'a> TyLoweringContext<'a> {
lifetime, lifetime,
}))) })))
} }
TypeBound::Error => None, TypeBound::Use(_) | TypeBound::Error => None,
}; };
clause.into_iter().chain( clause.into_iter().chain(
trait_ref trait_ref
@ -1087,6 +1087,7 @@ impl<'a> TyLoweringContext<'a> {
path.segments().last() path.segments().last()
} }
TypeBound::Path(_, TraitBoundModifier::Maybe) TypeBound::Path(_, TraitBoundModifier::Maybe)
| TypeBound::Use(_)
| TypeBound::Error | TypeBound::Error
| TypeBound::Lifetime(_) => None, | 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, WherePredicate::Lifetime { .. } => false,

View file

@ -144,10 +144,31 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
LIFETIME_IDENT => lifetime(p), LIFETIME_IDENT => lifetime(p),
T![for] => types::for_type(p, false), T![for] => types::for_type(p, false),
// test precise_capturing // 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![<]) => { T![use] if p.nth_at(1, T![<]) => {
p.bump_any(); 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]) => { T![?] if p.nth_at(1, T![for]) => {
// test question_for_type_trait_bound // test question_for_type_trait_bound

View file

@ -312,6 +312,8 @@ pub enum SyntaxKind {
UNDERSCORE_EXPR, UNDERSCORE_EXPR,
UNION, UNION,
USE, USE,
USE_BOUND_GENERIC_ARG,
USE_BOUND_GENERIC_ARGS,
USE_TREE, USE_TREE,
USE_TREE_LIST, USE_TREE_LIST,
VARIANT, VARIANT,

View file

@ -50,16 +50,18 @@ SOURCE_FILE
WHITESPACE " " WHITESPACE " "
TYPE_BOUND TYPE_BOUND
USE_KW "use" USE_KW "use"
GENERIC_PARAM_LIST USE_BOUND_GENERIC_ARGS
L_ANGLE "<" L_ANGLE "<"
LIFETIME_PARAM
LIFETIME LIFETIME
LIFETIME_IDENT "'b" LIFETIME_IDENT "'b"
COMMA "," COMMA ","
WHITESPACE " " WHITESPACE " "
TYPE_PARAM NAME_REF
NAME
IDENT "T" IDENT "T"
COMMA ","
WHITESPACE " "
NAME_REF
SELF_TYPE_KW "Self"
R_ANGLE ">" R_ANGLE ">"
WHITESPACE " " WHITESPACE " "
BLOCK_EXPR BLOCK_EXPR

View file

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

View file

@ -657,7 +657,14 @@ TypeBoundList =
TypeBound = TypeBound =
Lifetime Lifetime
| ('~' 'const' | 'const')? 'async'? '?'? Type | ('~' 'const' | 'const')? 'async'? '?'? Type
| 'use' GenericParamList | 'use' UseBoundGenericArgs
UseBoundGenericArgs =
'<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
UseBoundGenericArg =
Lifetime
| NameRef
//************************// //************************//
// Patterns // // Patterns //

View file

@ -1993,13 +1993,15 @@ pub struct TypeBound {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl TypeBound { impl TypeBound {
#[inline]
pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
#[inline] #[inline]
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
#[inline] #[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline] #[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![?]) } pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
#[inline] #[inline]
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } 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]) } 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)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UseTree { pub struct UseTree {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
@ -2402,6 +2419,12 @@ pub enum Type {
TupleType(TupleType), TupleType(TupleType),
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum UseBoundGenericArg {
Lifetime(Lifetime),
NameRef(NameRef),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AnyHasArgList { pub struct AnyHasArgList {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
@ -4435,6 +4458,20 @@ impl AstNode for Use {
#[inline] #[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax } 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 { impl AstNode for UseTree {
#[inline] #[inline]
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE } 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 { impl AnyHasArgList {
#[inline] #[inline]
pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList { 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) 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 { impl std::fmt::Display for Abi {
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)
@ -7275,6 +7345,11 @@ impl std::fmt::Display for Use {
std::fmt::Display::fmt(self.syntax(), f) 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 { impl std::fmt::Display for UseTree {
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)

View file

@ -795,7 +795,7 @@ pub enum TypeBoundKind {
/// for<'a> ... /// for<'a> ...
ForType(ast::ForType), ForType(ast::ForType),
/// use /// use
Use(ast::GenericParamList), Use(ast::UseBoundGenericArgs),
/// 'a /// 'a
Lifetime(ast::Lifetime), Lifetime(ast::Lifetime),
} }
@ -806,8 +806,8 @@ impl ast::TypeBound {
TypeBoundKind::PathType(path_type) TypeBoundKind::PathType(path_type)
} else if let Some(for_type) = support::children(self.syntax()).next() { } else if let Some(for_type) = support::children(self.syntax()).next() {
TypeBoundKind::ForType(for_type) TypeBoundKind::ForType(for_type)
} else if let Some(generic_param_list) = self.generic_param_list() { } else if let Some(args) = self.use_bound_generic_args() {
TypeBoundKind::Use(generic_param_list) TypeBoundKind::Use(args)
} else if let Some(lifetime) = self.lifetime() { } else if let Some(lifetime) = self.lifetime() {
TypeBoundKind::Lifetime(lifetime) TypeBoundKind::Lifetime(lifetime)
} else { } else {