From 8ecb486add8eb58dedc6fa88f2fe42e8941335c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 4 Aug 2023 17:22:20 +0000 Subject: [PATCH] Detect missing `;` that parses as function call Fix #106515. --- compiler/rustc_hir_typeck/src/callee.rs | 29 ++++--- ...ng-semicolon-between-call-and-tuple.stderr | 2 +- tests/ui/suggestions/missing-semicolon.fixed | 38 ++++++++++ tests/ui/suggestions/missing-semicolon.rs | 38 ++++++++++ tests/ui/suggestions/missing-semicolon.stderr | 75 +++++++++++++++++++ 5 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 tests/ui/suggestions/missing-semicolon.fixed create mode 100644 tests/ui/suggestions/missing-semicolon.rs create mode 100644 tests/ui/suggestions/missing-semicolon.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index c68f2d94f35..6810358405d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -645,18 +645,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) } hir::ExprKind::Call(ref inner_callee, _) => { - // If the call spans more than one line and the callee kind is - // itself another `ExprCall`, that's a clue that we might just be - // missing a semicolon (Issue #51055) - let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span); - if call_is_multiline { - err.span_suggestion( - callee_expr.span.shrink_to_hi(), - "consider using a semicolon here", - ";", - Applicability::MaybeIncorrect, - ); - } if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind { inner_callee_path = Some(inner_qpath); self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id) @@ -668,6 +656,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { + // If the call spans more than one line and the callee kind is + // itself another `ExprCall`, that's a clue that we might just be + // missing a semicolon (#51055, #106515). + let call_is_multiline = self + .tcx + .sess + .source_map() + .is_multiline(call_expr.span.with_lo(callee_expr.span.hi())) + && call_expr.span.ctxt() == callee_expr.span.ctxt(); + if call_is_multiline { + err.span_suggestion( + callee_expr.span.shrink_to_hi(), + "consider using a semicolon here to finish the statement", + ";", + Applicability::MaybeIncorrect, + ); + } if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) && !self.type_is_sized_modulo_regions(self.param_env, output_ty) { diff --git a/tests/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/tests/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr index 438075083d3..bb8b9b37067 100644 --- a/tests/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr +++ b/tests/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -5,7 +5,7 @@ LL | fn vindictive() -> bool { true } | ----------------------- `vindictive` defined here returns `bool` ... LL | vindictive() - | -^^^^^^^^^^^- help: consider using a semicolon here: `;` + | -^^^^^^^^^^^- help: consider using a semicolon here to finish the statement: `;` | _____| | | LL | | (1, 2) diff --git a/tests/ui/suggestions/missing-semicolon.fixed b/tests/ui/suggestions/missing-semicolon.fixed new file mode 100644 index 00000000000..df355f0b007 --- /dev/null +++ b/tests/ui/suggestions/missing-semicolon.fixed @@ -0,0 +1,38 @@ +// run-rustfix +#![allow(dead_code, unused_variables, path_statements)] +fn a() { + let x = 5; + let y = x; //~ ERROR expected function + (); //~ ERROR expected `;`, found `}` +} + +fn b() { + let x = 5; + let y = x; //~ ERROR expected function + (); +} +fn c() { + let x = 5; + x; //~ ERROR expected function + () +} +fn d() { // ok + let x = || (); + x + () +} +fn e() { // ok + let x = || (); + x + (); +} +fn f() + { + let y = 5; //~ ERROR expected function + (); //~ ERROR expected `;`, found `}` +} +fn g() { + 5; //~ ERROR expected function + (); +} +fn main() {} diff --git a/tests/ui/suggestions/missing-semicolon.rs b/tests/ui/suggestions/missing-semicolon.rs new file mode 100644 index 00000000000..12ef3d33e5f --- /dev/null +++ b/tests/ui/suggestions/missing-semicolon.rs @@ -0,0 +1,38 @@ +// run-rustfix +#![allow(dead_code, unused_variables, path_statements)] +fn a() { + let x = 5; + let y = x //~ ERROR expected function + () //~ ERROR expected `;`, found `}` +} + +fn b() { + let x = 5; + let y = x //~ ERROR expected function + (); +} +fn c() { + let x = 5; + x //~ ERROR expected function + () +} +fn d() { // ok + let x = || (); + x + () +} +fn e() { // ok + let x = || (); + x + (); +} +fn f() + { + let y = 5 //~ ERROR expected function + () //~ ERROR expected `;`, found `}` +} +fn g() { + 5 //~ ERROR expected function + (); +} +fn main() {} diff --git a/tests/ui/suggestions/missing-semicolon.stderr b/tests/ui/suggestions/missing-semicolon.stderr new file mode 100644 index 00000000000..54a64f664b5 --- /dev/null +++ b/tests/ui/suggestions/missing-semicolon.stderr @@ -0,0 +1,75 @@ +error: expected `;`, found `}` + --> $DIR/missing-semicolon.rs:6:7 + | +LL | () + | ^ help: add `;` here +LL | } + | - unexpected token + +error: expected `;`, found `}` + --> $DIR/missing-semicolon.rs:32:7 + | +LL | () + | ^ help: add `;` here +LL | } + | - unexpected token + +error[E0618]: expected function, found `{integer}` + --> $DIR/missing-semicolon.rs:5:13 + | +LL | let x = 5; + | - `x` has type `{integer}` +LL | let y = x + | ^- help: consider using a semicolon here to finish the statement: `;` + | _____________| + | | +LL | | () + | |______- call expression requires function + +error[E0618]: expected function, found `{integer}` + --> $DIR/missing-semicolon.rs:11:13 + | +LL | let x = 5; + | - `x` has type `{integer}` +LL | let y = x + | ^- help: consider using a semicolon here to finish the statement: `;` + | _____________| + | | +LL | | (); + | |______- call expression requires function + +error[E0618]: expected function, found `{integer}` + --> $DIR/missing-semicolon.rs:16:5 + | +LL | let x = 5; + | - `x` has type `{integer}` +LL | x + | ^- help: consider using a semicolon here to finish the statement: `;` + | _____| + | | +LL | | () + | |______- call expression requires function + +error[E0618]: expected function, found `{integer}` + --> $DIR/missing-semicolon.rs:31:13 + | +LL | let y = 5 + | ^- help: consider using a semicolon here to finish the statement: `;` + | _____________| + | | +LL | | () + | |______- call expression requires function + +error[E0618]: expected function, found `{integer}` + --> $DIR/missing-semicolon.rs:35:5 + | +LL | 5 + | ^- help: consider using a semicolon here to finish the statement: `;` + | _____| + | | +LL | | (); + | |______- call expression requires function + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0618`.