Skip to content

Commit 41389e6

Browse files
committed
Support length for ByteStrings
I am not confident that my added byte string parsing is right.
1 parent 30ce511 commit 41389e6

File tree

8 files changed

+85
-33
lines changed

8 files changed

+85
-33
lines changed

crates/hir_def/src/body/lower.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,10 @@ impl From<ast::LiteralKind> for Literal {
10121012
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
10131013
Literal::Float(Default::default(), ty)
10141014
}
1015-
LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
1015+
LiteralKind::ByteString(bs) => {
1016+
let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
1017+
Literal::ByteString(text)
1018+
}
10161019
LiteralKind::String(_) => Literal::String(Default::default()),
10171020
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
10181021
LiteralKind::Bool(val) => Literal::Bool(val),

crates/hir_ty/src/infer/expr.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ use stdx::always;
1616
use syntax::ast::RangeOp;
1717

1818
use crate::{
19-
autoderef, dummy_usize_const,
19+
autoderef,
2020
lower::lower_to_chalk_mutability,
2121
mapping::from_chalk,
2222
method_resolution, op,
2323
primitive::{self, UintTy},
2424
static_lifetime, to_chalk_trait_id,
2525
traits::FnTrait,
2626
utils::{generics, Generics},
27-
AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
28-
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27+
AdtId, Binders, CallableDefId, ConcreteConst, ConstValue, FnPointer, FnSig, FnSubst,
28+
InEnvironment, Interner, ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty,
29+
TyBuilder, TyExt, TyKind,
2930
};
3031

3132
use super::{
@@ -758,11 +759,18 @@ impl<'a> InferenceContext<'a> {
758759
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
759760
.intern(&Interner)
760761
}
761-
Literal::ByteString(..) => {
762+
Literal::ByteString(bs) => {
762763
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
763764

764-
let array_type =
765-
TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
765+
let len = ConstData {
766+
ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
767+
value: ConstValue::Concrete(ConcreteConst {
768+
interned: ConstScalar::Usize(bs.len() as u64),
769+
}),
770+
}
771+
.intern(&Interner);
772+
773+
let array_type = TyKind::Array(byte_type, len).intern(&Interner);
766774
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
767775
}
768776
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),

crates/hir_ty/src/tests/simple.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -496,15 +496,15 @@ fn infer_literals() {
496496
26..30 '5f32': f32
497497
36..40 '5f64': f64
498498
46..53 '"hello"': &str
499-
59..67 'b"bytes"': &[u8; _]
499+
59..67 'b"bytes"': &[u8; 5]
500500
73..76 ''c'': char
501501
82..86 'b'b'': u8
502502
92..96 '3.14': f64
503503
102..106 '5000': i32
504504
112..117 'false': bool
505505
123..127 'true': bool
506506
133..197 'r#" ... "#': &str
507-
203..213 'br#"yolo"#': &[u8; _]
507+
203..213 'br#"yolo"#': &[u8; 4]
508508
"##]],
509509
);
510510
}

crates/ide/src/join_lines.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ide_assists::utils::extract_trivial_expression;
44
use itertools::Itertools;
55
use syntax::{
66
algo::non_trivia_sibling,
7-
ast::{self, AstNode, AstToken},
7+
ast::{self, AstNode, AstToken, IsString},
88
Direction, NodeOrToken, SourceFile,
99
SyntaxKind::{self, USE_TREE, WHITESPACE},
1010
SyntaxNode, SyntaxToken, TextRange, TextSize, T,

crates/ide/src/syntax_highlighting/inject.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use either::Either;
66
use hir::{InFile, Semantics};
77
use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
88
use syntax::{
9-
ast::{self, AstNode},
9+
ast::{self, AstNode, IsString},
1010
AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
1111
};
1212

crates/ide_assists/src/handlers/raw_string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::borrow::Cow;
22

3-
use syntax::{ast, AstToken, TextRange, TextSize};
3+
use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
44

55
use crate::{AssistContext, AssistId, AssistKind, Assists};
66

crates/ide_assists/src/handlers/replace_string_with_char.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use syntax::{ast, AstToken, SyntaxKind::STRING};
1+
use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
22

33
use crate::{AssistContext, AssistId, AssistKind, Assists};
44

crates/syntax/src/ast/token_ext.rs

+61-20
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,30 @@ impl QuoteOffsets {
143143
}
144144
}
145145

146+
pub trait IsString: AstToken {
147+
fn quote_offsets(&self) -> Option<QuoteOffsets> {
148+
let text = self.text();
149+
let offsets = QuoteOffsets::new(text)?;
150+
let o = self.syntax().text_range().start();
151+
let offsets = QuoteOffsets {
152+
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
153+
contents: offsets.contents + o,
154+
};
155+
Some(offsets)
156+
}
157+
fn text_range_between_quotes(&self) -> Option<TextRange> {
158+
self.quote_offsets().map(|it| it.contents)
159+
}
160+
fn open_quote_text_range(&self) -> Option<TextRange> {
161+
self.quote_offsets().map(|it| it.quotes.0)
162+
}
163+
fn close_quote_text_range(&self) -> Option<TextRange> {
164+
self.quote_offsets().map(|it| it.quotes.1)
165+
}
166+
}
167+
168+
impl IsString for ast::String {}
169+
146170
impl ast::String {
147171
pub fn is_raw(&self) -> bool {
148172
self.text().starts_with('r')
@@ -187,32 +211,49 @@ impl ast::String {
187211
(false, false) => Some(Cow::Owned(buf)),
188212
}
189213
}
190-
191-
pub fn quote_offsets(&self) -> Option<QuoteOffsets> {
192-
let text = self.text();
193-
let offsets = QuoteOffsets::new(text)?;
194-
let o = self.syntax().text_range().start();
195-
let offsets = QuoteOffsets {
196-
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
197-
contents: offsets.contents + o,
198-
};
199-
Some(offsets)
200-
}
201-
pub fn text_range_between_quotes(&self) -> Option<TextRange> {
202-
self.quote_offsets().map(|it| it.contents)
203-
}
204-
pub fn open_quote_text_range(&self) -> Option<TextRange> {
205-
self.quote_offsets().map(|it| it.quotes.0)
206-
}
207-
pub fn close_quote_text_range(&self) -> Option<TextRange> {
208-
self.quote_offsets().map(|it| it.quotes.1)
209-
}
210214
}
211215

216+
impl IsString for ast::ByteString {}
217+
212218
impl ast::ByteString {
213219
pub fn is_raw(&self) -> bool {
214220
self.text().starts_with("br")
215221
}
222+
223+
pub fn value(&self) -> Option<Cow<'_, [u8]>> {
224+
if self.is_raw() {
225+
let text = self.text();
226+
let text =
227+
&text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
228+
return Some(Cow::Borrowed(text.as_bytes()));
229+
}
230+
231+
let text = self.text();
232+
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
233+
234+
let mut buf: Vec<u8> = Vec::new();
235+
let mut text_iter = text.chars();
236+
let mut has_error = false;
237+
unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
238+
unescaped_char,
239+
buf.capacity() == 0,
240+
) {
241+
(Ok(c), false) => buf.push(c as u8),
242+
(Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
243+
(Ok(c), true) => {
244+
buf.reserve_exact(text.len());
245+
buf.extend_from_slice(&text[..char_range.start].as_bytes());
246+
buf.push(c as u8);
247+
}
248+
(Err(_), _) => has_error = true,
249+
});
250+
251+
match (has_error, buf.capacity() == 0) {
252+
(true, _) => None,
253+
(false, true) => Some(Cow::Borrowed(text.as_bytes())),
254+
(false, false) => Some(Cow::Owned(buf)),
255+
}
256+
}
216257
}
217258

218259
#[derive(Debug)]

0 commit comments

Comments
 (0)