Skip to content

Commit

Permalink
Implement gen block and function parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
mohe2015 committed Dec 25, 2023
1 parent 76e592e commit af6a414
Show file tree
Hide file tree
Showing 30 changed files with 406 additions and 34 deletions.
4 changes: 4 additions & 0 deletions crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ impl FunctionData {
pub fn is_varargs(&self) -> bool {
self.flags.contains(FnFlags::IS_VARARGS)
}

pub fn has_gen_kw(&self) -> bool {
self.flags.contains(FnFlags::HAS_GEN_KW)
}
}

fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
Expand Down
1 change: 1 addition & 0 deletions crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ bitflags::bitflags! {
const HAS_ASYNC_KW = 1 << 4;
const HAS_UNSAFE_KW = 1 << 5;
const IS_VARARGS = 1 << 6;
const HAS_GEN_KW = 1 << 7;
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/hir-def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ impl<'a> Ctx<'a> {
if func.unsafe_token().is_some() {
flags |= FnFlags::HAS_UNSAFE_KW;
}
if func.gen_token().is_some() {
flags |= FnFlags::HAS_GEN_KW;
}

let mut res = Function {
name,
Expand Down
3 changes: 3 additions & 0 deletions crates/hir-def/src/item_tree/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ impl Printer<'_> {
if flags.contains(FnFlags::HAS_ASYNC_KW) {
w!(self, "async ");
}
if flags.contains(FnFlags::HAS_GEN_KW) {
w!(self, "gen ");
}
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
w!(self, "unsafe ");
}
Expand Down
15 changes: 15 additions & 0 deletions crates/hir-def/src/item_tree/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,18 @@ pub(self) struct S;
"#]],
)
}

#[test]
fn gen_fn() {
check(
r#"
gen fn test1() {}
async gen fn test2() {}
"#,
expect![[r#"
pub(self) gen fn test1() -> () { ... }
pub(self) async gen fn test2() -> impl ::core::future::Future::<Output = ()> { ... }
"#]],
)
}
10 changes: 6 additions & 4 deletions crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let Some(def) = self.owner.as_generic_def_id() else {
not_supported!("owner without generic def id");
};
let gen = generics(self.db.upcast(), def);
let r#gen = generics(self.db.upcast(), def);
let ty = self.expr_ty_without_adjust(expr_id);
self.push_assignment(
current,
Expand All @@ -486,9 +486,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
ty,
value: chalk_ir::ConstValue::BoundVar(BoundVar::new(
DebruijnIndex::INNERMOST,
gen.param_idx(p.into()).ok_or(MirLowerError::TypeError(
"fail to lower const generic param",
))?,
r#gen.param_idx(p.into()).ok_or(
MirLowerError::TypeError(
"fail to lower const generic param",
),
)?,
)),
}
.intern(Interner),
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-ty/src/tests/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ struct S<T> { a: T }
fn f<T>(_: &[T]) -> T { loop {} }
fn g<T>(_: S<&[T]>) -> T { loop {} }
fn gen<T>() -> *mut [T; 2] { loop {} }
fn r#gen<T>() -> *mut [T; 2] { loop {} }
fn test1<U>() -> *mut [U] {
gen()
r#gen()
}
fn test2() {
Expand Down
12 changes: 6 additions & 6 deletions crates/hir-ty/src/tests/never_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ fn test() {
fn infer_never2() {
check_types(
r#"
fn gen<T>() -> T { loop {} }
fn r#gen<T>() -> T { loop {} }
fn test() {
let a = gen();
let a = r#gen();
if false { a } else { loop {} };
a;
} //^ !
Expand All @@ -33,10 +33,10 @@ fn test() {
fn infer_never3() {
check_types(
r#"
fn gen<T>() -> T { loop {} }
fn r#gen<T>() -> T { loop {} }
fn test() {
let a = gen();
let a = r#gen();
if false { loop {} } else { a };
a;
//^ !
Expand All @@ -63,10 +63,10 @@ fn test() {
fn never_type_can_be_reinferred1() {
check_types(
r#"
fn gen<T>() -> T { loop {} }
fn r#gen<T>() -> T { loop {} }
fn test() {
let a = gen();
let a = r#gen();
if false { loop {} } else { a };
a;
//^ ()
Expand Down
3 changes: 3 additions & 0 deletions crates/hir/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ impl HirDisplay for Function {
if data.has_async_kw() {
f.write_str("async ")?;
}
if data.has_gen_kw() {
f.write_str("gen ")?;
}
if self.is_unsafe_to_call(db) {
f.write_str("unsafe ")?;
}
Expand Down
4 changes: 4 additions & 0 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,10 @@ impl Function {
db.function_data(self.id).has_async_kw()
}

pub fn is_gen(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).has_gen_kw()
}

/// Does this function have `#[test]` attribute?
pub fn is_test(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_test()
Expand Down
37 changes: 37 additions & 0 deletions crates/ide-assists/src/handlers/generate_delegate_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let is_async = method_source.async_token().is_some();
let is_const = method_source.const_token().is_some();
let is_unsafe = method_source.unsafe_token().is_some();
let is_gen = method_source.gen_token().is_some();
let tail_expr_finished =
if is_async { make::expr_await(tail_expr) } else { tail_expr };
let body = make::block_expr([], Some(tail_expr_finished));
Expand All @@ -138,6 +139,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
is_async,
is_const,
is_unsafe,
is_gen,
)
.clone_for_update();

Expand Down Expand Up @@ -705,4 +707,39 @@ impl Person {
"#,
);
}

#[test]
fn test_gen_fn() {
check_assist(
generate_delegate_methods,
r#"
struct Age(u8);
impl Age {
gen fn age(&self) -> u8 {
self.0
}
}
struct Person {
ag$0e: Age,
}"#,
r#"
struct Age(u8);
impl Age {
gen fn age(&self) -> u8 {
self.0
}
}
struct Person {
age: Age,
}
impl Person {
$0gen fn age(&self) -> u8 {
self.age.age()
}
}"#,
);
}
}
41 changes: 41 additions & 0 deletions crates/ide-assists/src/handlers/generate_delegate_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ fn func_assoc_item(
item.async_token().is_some(),
item.const_token().is_some(),
item.unsafe_token().is_some(),
item.gen_token().is_some(),
)
.clone_for_update();

Expand Down Expand Up @@ -1048,4 +1049,44 @@ impl some_module::SomeTrait for B {
}"#,
)
}

#[test]
fn test_gen_fn() {
check_assist(
generate_delegate_trait,
r#"
struct Base;
struct S {
ba$0se: Base,
}
trait Trait {
gen fn a_func();
}
impl Trait for Base {
gen fn a_func() {}
}
"#,
r#"
struct Base;
struct S {
base: Base,
}
impl Trait for S {
gen fn a_func() {
<Base as Trait>::a_func()
}
}
trait Trait {
gen fn a_func();
}
impl Trait for Base {
gen fn a_func() {}
}
"#,
);
}

}
3 changes: 2 additions & 1 deletion crates/ide-assists/src/handlers/generate_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ impl FunctionBuilder {
fn_body,
self.ret_type,
self.is_async,
false, // FIXME : const and unsafe are not handled yet.
false, // FIXME : const, unsafe and gen are not handled yet.
false,
false,
);
let leading_ws;
Expand Down
3 changes: 3 additions & 0 deletions crates/ide-completion/src/render/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
ret_ty = async_ret;
}
}
if func.is_gen(db) {
format_to!(detail, "gen ");
}
if func.is_unsafe_to_call(db) {
format_to!(detail, "unsafe ");
}
Expand Down
30 changes: 30 additions & 0 deletions crates/ide-completion/src/tests/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,36 @@ fn main() {
);
}

#[test]
fn detail_gen_fn() {
check_empty(
r#"
//- minicore: future, sized
gen fn foo() -> u8 {}
fn main() {
self::$0
}
"#,
expect![[r#"
fn foo() gen fn() -> u8
fn main() fn()
"#]],
);
check_empty(
r#"
//- minicore: future, sized
async gen fn foo() -> u8 {}
fn main() {
self::$0
}
"#,
expect![[r#"
fn foo() async gen fn() -> u8
fn main() fn()
"#]],
);
}

#[test]
fn detail_impl_trait_in_argument_position() {
check_empty(
Expand Down
8 changes: 4 additions & 4 deletions crates/ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1605,8 +1605,8 @@ where T : Bound
struct A;
impl Bound for A{}
fn f() {
let gen = Gen::<A>(A);
gen.g$0();
let r#gen = Gen::<A>(A);
r#gen.g$0();
}
"#,
);
Expand All @@ -1631,8 +1631,8 @@ where T : Bound
struct A;
impl Bound for A{}
fn f() {
let gen = Gen::<A>(A);
gen.g$0();
let r#gen = Gen::<A>(A);
r#gen.g$0();
}
"#,
);
Expand Down
28 changes: 28 additions & 0 deletions crates/ide/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,34 @@ fn test_hover_function_show_qualifiers() {
```
"#]],
);
check(
r#"async gen fn foo$0() {}"#,
expect![[r#"
*foo*
```rust
test
```
```rust
async gen fn foo()
```
"#]],
);
check(
r#"gen fn foo$0() {}"#,
expect![[r#"
*foo*
```rust
test
```
```rust
gen fn foo()
```
"#]],
);
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions crates/ide/src/inlay_hints/fn_lifetime_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ pub(super) fn hints(

// allocate names
let mut gen_idx_name = {
let mut gen = (0u8..).map(|idx| match idx {
let mut r#gen = (0u8..).map(|idx| match idx {
idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
idx => format!("'{idx}").into(),
});
move || gen.next().unwrap_or_default()
move || r#gen.next().unwrap_or_default()
};
let mut allocated_lifetimes = vec![];

Expand Down
Loading

0 comments on commit af6a414

Please sign in to comment.