Auto merge of #18371 - Veykril:veykril/push-kwttrusywysp, r=Veykril

fix: Fix incorrect parsing of use bounds

Fixes https://github.com/rust-lang/rust-analyzer/issues/18357
This commit is contained in:
bors 2024-10-22 11:42:11 +00:00
commit 919ba41fee
11 changed files with 184 additions and 25 deletions

View File

@ -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 @@ fn go(type_ref: &TypeRef, f: &mut impl FnMut(&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 @@ fn go_path(path: &Path, f: &mut impl FnMut(&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 @@ pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::TypeBound) -> Self {
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 @@ pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
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,
}
}
}

View File

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

View File

@ -19,7 +19,7 @@
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
)?;
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}}"),
}
}

View File

@ -1067,7 +1067,7 @@ pub(crate) fn lower_type_bound(
lifetime,
})))
}
TypeBound::Error => None,
TypeBound::Use(_) | TypeBound::Error => None,
};
clause.into_iter().chain(
trait_ref
@ -1087,6 +1087,7 @@ fn assoc_type_bindings_from_type_bound(
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,

View File

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

View File

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

View File

@ -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"
COMMA ","
WHITESPACE " "
TYPE_PARAM
NAME
NAME_REF
IDENT "T"
COMMA ","
WHITESPACE " "
NAME_REF
SELF_TYPE_KW "Self"
R_ANGLE ">"
WHITESPACE " "
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 =
Lifetime
| ('~' 'const' | 'const')? 'async'? '?'? Type
| 'use' GenericParamList
| 'use' UseBoundGenericArgs
UseBoundGenericArgs =
'<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
UseBoundGenericArg =
Lifetime
| NameRef
//************************//
// Patterns //

View File

@ -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 @@ pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
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 @@ fn cast(syntax: SyntaxNode) -> Option<Self> {
#[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 @@ fn syntax(&self) -> &SyntaxNode {
}
}
}
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 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
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 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
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)

View File

@ -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 @@ pub fn kind(&self) -> TypeBoundKind {
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 {