From 2876a11c329f92d83c334b95c4cb6704357dc21b Mon Sep 17 00:00:00 2001 From: Tilak Madichetti Date: Thu, 12 Dec 2024 22:29:54 +0530 Subject: [PATCH] feat: underscores and literals validation (#165) * feat: remove trailing underscores * literals * fix * fix: remove print statement * fix: suggestions * demo expr recursed * Update crates/sema/src/ast_passes.rs --------- Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/sema/src/ast_passes.rs | 45 ++++++++++++--- tests/ui/resolve/literals_underscores.sol | 14 +++++ tests/ui/resolve/literals_underscores.stderr | 58 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 tests/ui/resolve/literals_underscores.sol create mode 100644 tests/ui/resolve/literals_underscores.stderr diff --git a/crates/sema/src/ast_passes.rs b/crates/sema/src/ast_passes.rs index cc007f47..58e77ac8 100644 --- a/crates/sema/src/ast_passes.rs +++ b/crates/sema/src/ast_passes.rs @@ -60,6 +60,38 @@ impl<'sess> AstValidator<'sess, '_> { .emit(); } } + + fn check_underscores_in_number_literals(&self, lit: &ast::Lit) { + let ast::LitKind::Number(_) = lit.kind else { + return; + }; + let literal_span = lit.span; + let literal_str = lit.symbol.as_str(); + + let error_help_msg = { + if literal_str.ends_with('_') { + Some("remove trailing underscores") + } else if literal_str.contains("__") { + Some("only 1 consecutive underscore `_` is allowed between digits") + } else if literal_str.contains("._") || literal_str.contains("_.") { + Some("remove underscores in front of the fraction part") + } else if literal_str.contains("_e") { + Some("remove underscores at the end of the mantissa") + } else if literal_str.contains("e_") { + Some("remove underscores in front of the exponent") + } else { + None + } + }; + + if let Some(error_help_msg) = error_help_msg { + self.dcx() + .err("invalid use of underscores in number literal") + .span(literal_span) + .help(error_help_msg) + .emit(); + } + } } impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> { @@ -329,12 +361,11 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> { self.walk_using_directive(using) } - // Intentionally override unused default implementations to reduce bloat. - fn visit_expr(&mut self, _expr: &'ast ast::Expr<'ast>) -> ControlFlow { - ControlFlow::Continue(()) - } - - fn visit_ty(&mut self, _ty: &'ast ast::Type<'ast>) -> ControlFlow { - ControlFlow::Continue(()) + fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow { + let ast::Expr { kind, .. } = expr; + if let ast::ExprKind::Lit(lit, _) = kind { + self.check_underscores_in_number_literals(lit); + } + self.walk_expr(expr) } } diff --git a/tests/ui/resolve/literals_underscores.sol b/tests/ui/resolve/literals_underscores.sol new file mode 100644 index 00000000..99270d26 --- /dev/null +++ b/tests/ui/resolve/literals_underscores.sol @@ -0,0 +1,14 @@ +contract LT { + uint256 a = 1000_; //~ERROR: invalid use of underscores in number literal + uint256 b = 100__0; //~ERROR: invalid use of underscores in number literal + uint256 c = 1_.4e10; //~ERROR: invalid use of underscores in number literal + uint256 d = 3.4_e10; //~ERROR: invalid use of underscores in number literal + uint256 e = 3.4e_10; //~ERROR: invalid use of underscores in number literal + + // exception + uint256 f = 3._4e10; // Does not show up + + uint256 g = 1_.4e10 + 3.4e_10; //~ERROR: invalid use of underscores in number literal + //~^ERROR: invalid use of underscores in number literal + +} diff --git a/tests/ui/resolve/literals_underscores.stderr b/tests/ui/resolve/literals_underscores.stderr new file mode 100644 index 00000000..1a13d92c --- /dev/null +++ b/tests/ui/resolve/literals_underscores.stderr @@ -0,0 +1,58 @@ +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 a = 1000_; + | ^^^^^ + | + = help: remove trailing underscores + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 b = 100__0; + | ^^^^^^ + | + = help: only 1 consecutive underscore `_` is allowed between digits + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 c = 1_.4e10; + | ^^^^^^^ + | + = help: remove underscores in front of the fraction part + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 d = 3.4_e10; + | ^^^^^^^ + | + = help: remove underscores at the end of the mantissa + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 e = 3.4e_10; + | ^^^^^^^ + | + = help: remove underscores in front of the exponent + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 g = 1_.4e10 + 3.4e_10; + | ^^^^^^^ + | + = help: remove underscores in front of the fraction part + +error: invalid use of underscores in number literal + --> ROOT/tests/ui/resolve/literals_underscores.sol:LL:CC + | +LL | uint256 g = 1_.4e10 + 3.4e_10; + | ^^^^^^^ + | + = help: remove underscores in front of the exponent + +error: aborting due to 7 previous errors +