Unnamed repository; edit this file 'description' to name the repository.
Lower values of char and byte literals
Laurențiu Nicola 2022-05-05
parent 0218aeb · commit 9856144
-rw-r--r--crates/hir-def/src/body/lower.rs6
-rw-r--r--crates/ide/src/hover/tests.rs88
-rw-r--r--crates/rust-analyzer/src/lib.rs1
-rw-r--r--crates/syntax/src/ast/expr_ext.rs12
-rw-r--r--crates/syntax/src/ast/generated/tokens.rs42
-rw-r--r--crates/syntax/src/ast/token_ext.rs34
-rw-r--r--crates/syntax/src/tests/sourcegen_ast.rs2
-rw-r--r--crates/syntax/src/validation.rs4
8 files changed, 178 insertions, 11 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index f0cb39ec36..e8303ec40f 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -983,9 +983,11 @@ impl From<ast::LiteralKind> for Literal {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
Literal::String(text)
}
- LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
+ LiteralKind::Byte(b) => {
+ Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
+ }
+ LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
LiteralKind::Bool(val) => Literal::Bool(val),
- LiteralKind::Char => Literal::Char(Default::default()),
}
}
}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 95420f2ffe..74c5c98689 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3510,6 +3510,94 @@ const FOO$0: &str = "bar";
This is a doc
"#]],
);
+ // show char literal
+ check(
+ r#"
+/// This is a doc
+const FOO$0: char = 'a';
+"#,
+ expect![[r#"
+ *FOO*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ const FOO: char = 'a'
+ ```
+
+ ---
+
+ This is a doc
+ "#]],
+ );
+ // show escaped char literal
+ check(
+ r#"
+/// This is a doc
+const FOO$0: char = '\x61';
+"#,
+ expect![[r#"
+ *FOO*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ const FOO: char = 'a'
+ ```
+
+ ---
+
+ This is a doc
+ "#]],
+ );
+ // show byte literal
+ check(
+ r#"
+/// This is a doc
+const FOO$0: u8 = b'a';
+"#,
+ expect![[r#"
+ *FOO*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ const FOO: u8 = 97 (0x61)
+ ```
+
+ ---
+
+ This is a doc
+ "#]],
+ );
+ // show escaped byte literal
+ check(
+ r#"
+/// This is a doc
+const FOO$0: u8 = b'\x61';
+"#,
+ expect![[r#"
+ *FOO*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ const FOO: u8 = 97 (0x61)
+ ```
+
+ ---
+
+ This is a doc
+ "#]],
+ );
}
#[test]
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index d29ec512d6..3b9e201f57 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -8,7 +8,6 @@
//!
//! The `cli` submodule implements some batch-processing analysis, primarily as
//! a debugging aid.
-#![recursion_limit = "512"]
pub mod cli;
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index 1d0f393ec1..17785152bc 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -283,8 +283,8 @@ pub enum LiteralKind {
ByteString(ast::ByteString),
IntNumber(ast::IntNumber),
FloatNumber(ast::FloatNumber),
- Char,
- Byte,
+ Char(ast::Char),
+ Byte(ast::Byte),
Bool(bool),
}
@@ -312,12 +312,16 @@ impl ast::Literal {
if let Some(t) = ast::ByteString::cast(token.clone()) {
return LiteralKind::ByteString(t);
}
+ if let Some(t) = ast::Char::cast(token.clone()) {
+ return LiteralKind::Char(t);
+ }
+ if let Some(t) = ast::Byte::cast(token.clone()) {
+ return LiteralKind::Byte(t);
+ }
match token.kind() {
T![true] => LiteralKind::Bool(true),
T![false] => LiteralKind::Bool(false),
- CHAR => LiteralKind::Char,
- BYTE => LiteralKind::Byte,
_ => unreachable!(),
}
}
diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs
index 30f23b9d96..a3209c5abd 100644
--- a/crates/syntax/src/ast/generated/tokens.rs
+++ b/crates/syntax/src/ast/generated/tokens.rs
@@ -133,6 +133,48 @@ impl AstToken for FloatNumber {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Char {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Char {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Char {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Byte {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Byte {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Byte {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Ident {
pub(crate) syntax: SyntaxToken,
}
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index f1e5c2136f..4b6dc236b5 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -2,7 +2,7 @@
use std::borrow::Cow;
-use rustc_lexer::unescape::{unescape_literal, Mode};
+use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
use crate::{
ast::{self, AstToken},
@@ -406,3 +406,35 @@ mod tests {
check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
}
}
+
+impl ast::Char {
+ pub fn value(&self) -> Option<char> {
+ let mut text = self.text();
+ if text.starts_with('\'') {
+ text = &text[1..];
+ } else {
+ return None;
+ }
+ if text.ends_with('\'') {
+ text = &text[0..text.len() - 1];
+ }
+
+ unescape_char(text).ok()
+ }
+}
+
+impl ast::Byte {
+ pub fn value(&self) -> Option<u8> {
+ let mut text = self.text();
+ if text.starts_with("b\'") {
+ text = &text[2..];
+ } else {
+ return None;
+ }
+ if text.ends_with('\'') {
+ text = &text[0..text.len() - 1];
+ }
+
+ unescape_byte(text).ok()
+ }
+}
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index c2ed3eab0a..4cfb8075cb 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -585,7 +585,7 @@ impl Field {
fn lower(grammar: &Grammar) -> AstSrc {
let mut res = AstSrc {
- tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Ident"
+ tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Char Byte Ident"
.split_ascii_whitespace()
.map(|it| it.to_string())
.collect::<Vec<_>>(),
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 286affbba9..c2c2c82e11 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -151,12 +151,12 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
}
}
}
- ast::LiteralKind::Char => {
+ ast::LiteralKind::Char(_) => {
if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
push_err(1, e);
}
}
- ast::LiteralKind::Byte => {
+ ast::LiteralKind::Byte(_) => {
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
push_err(2, e);
}