mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
fix: don't use control flow when extracted fn contains tail expr of original fn
This commit is contained in:
parent
2f6d545535
commit
595d9e6ebb
1 changed files with 57 additions and 62 deletions
|
@ -1385,31 +1385,30 @@ enum FlowHandler {
|
||||||
|
|
||||||
impl FlowHandler {
|
impl FlowHandler {
|
||||||
fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
|
fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
|
||||||
match &fun.control_flow.kind {
|
if fun.contains_tail_expr {
|
||||||
None => FlowHandler::None,
|
return FlowHandler::None;
|
||||||
Some(flow_kind) => {
|
}
|
||||||
let action = flow_kind.clone();
|
let Some(action) = fun.control_flow.kind.clone() else {
|
||||||
if let FunType::Unit = ret_ty {
|
return FlowHandler::None;
|
||||||
match flow_kind {
|
};
|
||||||
FlowKind::Return(None)
|
|
||||||
| FlowKind::Break(_, None)
|
if let FunType::Unit = ret_ty {
|
||||||
| FlowKind::Continue(_) => FlowHandler::If { action },
|
match action {
|
||||||
FlowKind::Return(_) | FlowKind::Break(_, _) => {
|
FlowKind::Return(None) | FlowKind::Break(_, None) | FlowKind::Continue(_) => {
|
||||||
FlowHandler::IfOption { action }
|
FlowHandler::If { action }
|
||||||
}
|
|
||||||
FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match flow_kind {
|
|
||||||
FlowKind::Return(None)
|
|
||||||
| FlowKind::Break(_, None)
|
|
||||||
| FlowKind::Continue(_) => FlowHandler::MatchOption { none: action },
|
|
||||||
FlowKind::Return(_) | FlowKind::Break(_, _) => {
|
|
||||||
FlowHandler::MatchResult { err: action }
|
|
||||||
}
|
|
||||||
FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
FlowKind::Return(_) | FlowKind::Break(_, _) => FlowHandler::IfOption { action },
|
||||||
|
FlowKind::Try { kind } => FlowHandler::Try { kind },
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match action {
|
||||||
|
FlowKind::Return(None) | FlowKind::Break(_, None) | FlowKind::Continue(_) => {
|
||||||
|
FlowHandler::MatchOption { none: action }
|
||||||
|
}
|
||||||
|
FlowKind::Return(_) | FlowKind::Break(_, _) => {
|
||||||
|
FlowHandler::MatchResult { err: action }
|
||||||
|
}
|
||||||
|
FlowKind::Try { kind } => FlowHandler::Try { kind },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1654,11 +1653,7 @@ impl Function {
|
||||||
|
|
||||||
fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option<ast::RetType> {
|
fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option<ast::RetType> {
|
||||||
let fun_ty = self.return_type(ctx);
|
let fun_ty = self.return_type(ctx);
|
||||||
let handler = if self.contains_tail_expr {
|
let handler = FlowHandler::from_ret_ty(self, &fun_ty);
|
||||||
FlowHandler::None
|
|
||||||
} else {
|
|
||||||
FlowHandler::from_ret_ty(self, &fun_ty)
|
|
||||||
};
|
|
||||||
let ret_ty = match &handler {
|
let ret_ty = match &handler {
|
||||||
FlowHandler::None => {
|
FlowHandler::None => {
|
||||||
if matches!(fun_ty, FunType::Unit) {
|
if matches!(fun_ty, FunType::Unit) {
|
||||||
|
@ -1728,11 +1723,7 @@ fn make_body(
|
||||||
fun: &Function,
|
fun: &Function,
|
||||||
) -> ast::BlockExpr {
|
) -> ast::BlockExpr {
|
||||||
let ret_ty = fun.return_type(ctx);
|
let ret_ty = fun.return_type(ctx);
|
||||||
let handler = if fun.contains_tail_expr {
|
let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
|
||||||
FlowHandler::None
|
|
||||||
} else {
|
|
||||||
FlowHandler::from_ret_ty(fun, &ret_ty)
|
|
||||||
};
|
|
||||||
|
|
||||||
let block = match &fun.body {
|
let block = match &fun.body {
|
||||||
FunctionBody::Expr(expr) => {
|
FunctionBody::Expr(expr) => {
|
||||||
|
@ -4471,7 +4462,7 @@ async fn foo() -> Result<(), ()> {
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
async fn foo() -> Result<(), ()> {
|
async fn foo() -> Result<(), ()> {
|
||||||
fun_name().await?
|
fun_name().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn $0fun_name() -> Result<(), ()> {
|
async fn $0fun_name() -> Result<(), ()> {
|
||||||
|
@ -4690,7 +4681,7 @@ fn $0fun_name() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_function,
|
extract_function,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: result
|
//- minicore: result, try
|
||||||
fn foo() -> Result<(), i64> {
|
fn foo() -> Result<(), i64> {
|
||||||
$0Result::<i32, i64>::Ok(0)?;
|
$0Result::<i32, i64>::Ok(0)?;
|
||||||
Ok(())$0
|
Ok(())$0
|
||||||
|
@ -4698,7 +4689,7 @@ fn foo() -> Result<(), i64> {
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
fn foo() -> Result<(), i64> {
|
fn foo() -> Result<(), i64> {
|
||||||
fun_name()?
|
fun_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn $0fun_name() -> Result<(), i64> {
|
fn $0fun_name() -> Result<(), i64> {
|
||||||
|
@ -5753,6 +5744,34 @@ fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tail_expr_no_extra_control_flow() {
|
||||||
|
check_assist(
|
||||||
|
extract_function,
|
||||||
|
r#"
|
||||||
|
//- minicore: result
|
||||||
|
fn fallible() -> Result<(), ()> {
|
||||||
|
$0if true {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(())$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn fallible() -> Result<(), ()> {
|
||||||
|
fun_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn $0fun_name() -> Result<(), ()> {
|
||||||
|
if true {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_tail_expr_of_tail_expr_loop() {
|
fn non_tail_expr_of_tail_expr_loop() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -5800,12 +5819,6 @@ fn $0fun_name() -> ControlFlow<()> {
|
||||||
extract_function,
|
extract_function,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: option, try
|
//- minicore: option, try
|
||||||
impl<T> core::ops::Try for Option<T> {
|
|
||||||
type Output = T;
|
|
||||||
type Residual = Option<!>;
|
|
||||||
}
|
|
||||||
impl<T> core::ops::FromResidual for Option<T> {}
|
|
||||||
|
|
||||||
fn f() -> Option<()> {
|
fn f() -> Option<()> {
|
||||||
if true {
|
if true {
|
||||||
let a = $0if true {
|
let a = $0if true {
|
||||||
|
@ -5820,12 +5833,6 @@ fn f() -> Option<()> {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
impl<T> core::ops::Try for Option<T> {
|
|
||||||
type Output = T;
|
|
||||||
type Residual = Option<!>;
|
|
||||||
}
|
|
||||||
impl<T> core::ops::FromResidual for Option<T> {}
|
|
||||||
|
|
||||||
fn f() -> Option<()> {
|
fn f() -> Option<()> {
|
||||||
if true {
|
if true {
|
||||||
let a = fun_name()?;;
|
let a = fun_name()?;;
|
||||||
|
@ -5852,12 +5859,6 @@ fn $0fun_name() -> Option<()> {
|
||||||
extract_function,
|
extract_function,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: option, try
|
//- minicore: option, try
|
||||||
impl<T> core::ops::Try for Option<T> {
|
|
||||||
type Output = T;
|
|
||||||
type Residual = Option<!>;
|
|
||||||
}
|
|
||||||
impl<T> core::ops::FromResidual for Option<T> {}
|
|
||||||
|
|
||||||
fn f() -> Option<()> {
|
fn f() -> Option<()> {
|
||||||
if true {
|
if true {
|
||||||
$0{
|
$0{
|
||||||
|
@ -5874,15 +5875,9 @@ fn f() -> Option<()> {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
impl<T> core::ops::Try for Option<T> {
|
|
||||||
type Output = T;
|
|
||||||
type Residual = Option<!>;
|
|
||||||
}
|
|
||||||
impl<T> core::ops::FromResidual for Option<T> {}
|
|
||||||
|
|
||||||
fn f() -> Option<()> {
|
fn f() -> Option<()> {
|
||||||
if true {
|
if true {
|
||||||
fun_name()?
|
fun_name()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue