Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/hir/type_ref.rs27
-rw-r--r--crates/hir-def/src/pretty.rs23
-rw-r--r--crates/hir-ty/src/display.rs15
-rw-r--r--crates/hir-ty/src/lower.rs5
-rw-r--r--crates/parser/src/grammar/generic_params.rs25
-rw-r--r--crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--crates/parser/test_data/parser/inline/ok/precise_capturing.rast16
-rw-r--r--crates/parser/test_data/parser/inline/ok/precise_capturing.rs2
-rw-r--r--crates/syntax/rust.ungram9
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs79
-rw-r--r--crates/syntax/src/ast/node_ext.rs6
11 files changed, 184 insertions, 25 deletions
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index b74cd90f69..5fba206693 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -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,
}
}
}
diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs
index d5ef17a91f..49c0ad4124 100644
--- a/crates/hir-def/src/pretty.rs
+++ b/crates/hir-def/src/pretty.rs
@@ -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}}")?,
}
}
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 10f5bcdad8..79861345b8 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -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}}"),
}
}
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index c7ed68448b..f7db948998 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -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,
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs
index ecfabca092..92311238c2 100644
--- a/crates/parser/src/grammar/generic_params.rs
+++ b/crates/parser/src/grammar/generic_params.rs
@@ -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
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 8da338c0a2..21730244a3 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -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,
diff --git a/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
index cf52f1e479..f9c0a245af 100644
--- a/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
+++ b/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
@@ -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
diff --git a/crates/parser/test_data/parser/inline/ok/precise_capturing.rs b/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
index ec208d5062..9ac2305f3a 100644
--- a/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
+++ b/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
@@ -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> {}
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 90441c27f6..3609da0bb2 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -657,7 +657,14 @@ TypeBoundList =
TypeBound =
Lifetime
| ('~' 'const' | 'const')? 'async'? '?'? Type
-| 'use' GenericParamList
+| 'use' UseBoundGenericArgs
+
+UseBoundGenericArgs =
+ '<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
+
+UseBoundGenericArg =
+ Lifetime
+| NameRef
//************************//
// Patterns //
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 4f8bff489c..b9eb1abb11 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1994,12 +1994,14 @@ pub struct TypeBound {
}
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]) }
@@ -2077,6 +2079,21 @@ impl 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,
}
@@ -2403,6 +2420,12 @@ pub enum Type {
}
#[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)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 693bfe330b..11f5e662e3 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -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 {