diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-16 14:01:09 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-16 14:01:09 +0000 |
commit | 88e8b0a5fa17075475c75941932056f7289c5bcf (patch) | |
tree | 84889038ca64a9ee4775ecf5605ed0213b90a0b7 /crates/hir/src | |
parent | 00d5a9563af9c84cdea9d029a9583be0513cc459 (diff) | |
parent | 37a8cec6386d57e76b3067af48c78867aa9922ed (diff) |
Merge #7620
7620: Support control flow in `extract_function` assist r=matklad a=cpud36
Support `return`ing from outer function, `break`ing and `continue`ing outer loops when extracting function.
# Example
Transforms
```rust
fn foo() -> i32 {
let items = [1,2,3];
let mut sum = 0;
for &item in items {
<|>if item == 42 {
break;
}<|>
sum += item;
}
sum
}
```
Into
```rust
fn foo() -> i32 {
let items = [1,2,3];
let mut sum = 0;
for &item in items {
if fun_name(item) {
break;
}
sum += item;
}
sum
}
fn fun_name(item: i32) -> bool {
if item == 42 {
return true;
}
false
}
```
![add_explicit_type_infer_type](https://user-images.githubusercontent.com/4218373/107544222-0fadf280-6bdb-11eb-9625-ed6194ba92c0.gif)
# Features
Supported variants
- break and function does not return => uses `bool` and plain if
- break and function does return => uses `Option<T>` and matches on it
- break with value and function does not return => uses `Option<T>` and if let
- break with value and function does return => uses `Result<T, U>` and matches on t
- same for `return` and `continue`(but we can't continue with value)
Assist does handle nested loops and nested items(like functions, modules, impls)
Try `expr?` operator is allowed together with `return Err(_)` and `return None`.
`return expr` is not allowed.
# Not supported
## Mixing `return` with `break` or `continue`
If we have e.g. a `return` and a `break` in the selected code, it is unclear what the produced code should look like.
We can try `Result<T, Option<U>>` or something like that, but it isn't idiomatic, nor it is established. Otherwise, implementation
is relatively simple.
## `break` with label
Not sure how to handle different labels for multiple `break`s.
[edit] implemented try `expr?`
Co-authored-by: Vladyslav Katasonov <[email protected]>
Diffstat (limited to 'crates/hir/src')
-rw-r--r-- | crates/hir/src/code_model.rs | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 35b532602..7d43d4097 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -1802,6 +1802,18 @@ impl Type { | |||
1802 | None | 1802 | None |
1803 | } | 1803 | } |
1804 | 1804 | ||
1805 | pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { | ||
1806 | let ty = self.ty.value.strip_references(); | ||
1807 | let substs = match ty { | ||
1808 | Ty::Apply(apply_ty) => &apply_ty.parameters, | ||
1809 | Ty::Opaque(opaque_ty) => &opaque_ty.parameters, | ||
1810 | _ => return Either::Left(iter::empty()), | ||
1811 | }; | ||
1812 | |||
1813 | let iter = substs.iter().map(move |ty| self.derived(ty.clone())); | ||
1814 | Either::Right(iter) | ||
1815 | } | ||
1816 | |||
1805 | pub fn iterate_method_candidates<T>( | 1817 | pub fn iterate_method_candidates<T>( |
1806 | &self, | 1818 | &self, |
1807 | db: &dyn HirDatabase, | 1819 | db: &dyn HirDatabase, |