Skip to content

Commit

Permalink
fix: Fix incorrect parsing of use bounds
Browse files Browse the repository at this point in the history
Also lower them a bit more
  • Loading branch information
Veykril committed Oct 22, 2024
1 parent 17055aa commit 95298a2
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 25 deletions.
27 changes: 23 additions & 4 deletions crates/hir-def/src/hir/type_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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(_) => (),
}
}
}
Expand Down Expand Up @@ -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(_) => (),
}
}
}
Expand Down Expand Up @@ -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))
}
Expand All @@ -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,
}
}
}
Expand Down
23 changes: 21 additions & 2 deletions crates/hir-def/src/pretty.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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(
Expand Down Expand Up @@ -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}}")?,
}
}
Expand Down
15 changes: 14 additions & 1 deletion crates/hir-ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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}}"),
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/hir-ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ impl<'a> TyLoweringContext<'a> {
lifetime,
})))
}
TypeBound::Error => None,
TypeBound::Use(_) | TypeBound::Error => None,
};
clause.into_iter().chain(
trait_ref
Expand All @@ -1087,6 +1087,7 @@ impl<'a> TyLoweringContext<'a> {
path.segments().last()
}
TypeBound::Path(_, TraitBoundModifier::Maybe)
| TypeBound::Use(_)
| TypeBound::Error
| TypeBound::Lifetime(_) => None,
};
Expand Down Expand Up @@ -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,
Expand Down
25 changes: 23 additions & 2 deletions crates/parser/src/grammar/generic_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions crates/parser/src/syntax_kind/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
16 changes: 9 additions & 7 deletions crates/parser/test_data/parser/inline/ok/precise_capturing.rast
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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> {}
9 changes: 8 additions & 1 deletion crates/syntax/rust.ungram
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,14 @@ TypeBoundList =
TypeBound =
Lifetime
| ('~' 'const' | 'const')? 'async'? '?'? Type
| 'use' GenericParamList
| 'use' UseBoundGenericArgs

UseBoundGenericArgs =
'<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'

UseBoundGenericArg =
Lifetime
| NameRef

//************************//
// Patterns //
Expand Down
79 changes: 77 additions & 2 deletions crates/syntax/src/ast/generated/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]) }
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 95298a2

Please sign in to comment.