aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorJade <[email protected]>2021-05-12 13:44:01 +0100
committerJade <[email protected]>2021-05-13 05:22:46 +0100
commit73023c0299d4adeada026648c3684621f129e038 (patch)
tree302ca449ae51a546d808d93037134af9c470d6b5 /crates
parent8b147624ff906a11134d2e18be071c6cb8ec4beb (diff)
Support length for ByteStrings
I am not confident that my added byte string parsing is right.
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/body/lower.rs5
-rw-r--r--crates/hir_ty/src/infer/expr.rs20
-rw-r--r--crates/hir_ty/src/tests/simple.rs4
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--crates/ide_assists/src/handlers/raw_string.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_string_with_char.rs2
-rw-r--r--crates/syntax/src/ast/token_ext.rs81
8 files changed, 85 insertions, 33 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 9f278d35b..b00dcbdf0 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1022,7 +1022,10 @@ impl From<ast::LiteralKind> for Literal {
1022 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); 1022 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
1023 Literal::Float(Default::default(), ty) 1023 Literal::Float(Default::default(), ty)
1024 } 1024 }
1025 LiteralKind::ByteString(_) => Literal::ByteString(Default::default()), 1025 LiteralKind::ByteString(bs) => {
1026 let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
1027 Literal::ByteString(text)
1028 }
1026 LiteralKind::String(_) => Literal::String(Default::default()), 1029 LiteralKind::String(_) => Literal::String(Default::default()),
1027 LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)), 1030 LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
1028 LiteralKind::Bool(val) => Literal::Bool(val), 1031 LiteralKind::Bool(val) => Literal::Bool(val),
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 5e9420752..46e4777a4 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -16,7 +16,7 @@ use stdx::always;
16use syntax::ast::RangeOp; 16use syntax::ast::RangeOp;
17 17
18use crate::{ 18use crate::{
19 autoderef, dummy_usize_const, 19 autoderef,
20 lower::lower_to_chalk_mutability, 20 lower::lower_to_chalk_mutability,
21 mapping::from_chalk, 21 mapping::from_chalk,
22 method_resolution, op, 22 method_resolution, op,
@@ -24,8 +24,9 @@ use crate::{
24 static_lifetime, to_chalk_trait_id, 24 static_lifetime, to_chalk_trait_id,
25 traits::FnTrait, 25 traits::FnTrait,
26 utils::{generics, Generics}, 26 utils::{generics, Generics},
27 AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 27 AdtId, Binders, CallableDefId, ConcreteConst, ConstValue, FnPointer, FnSig, FnSubst,
28 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, 28 InEnvironment, Interner, ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty,
29 TyBuilder, TyExt, TyKind,
29}; 30};
30 31
31use super::{ 32use super::{
@@ -758,11 +759,18 @@ impl<'a> InferenceContext<'a> {
758 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner)) 759 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
759 .intern(&Interner) 760 .intern(&Interner)
760 } 761 }
761 Literal::ByteString(..) => { 762 Literal::ByteString(bs) => {
762 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 763 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
763 764
764 let array_type = 765 let len = ConstData {
765 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner); 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);
766 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner) 774 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
767 } 775 }
768 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner), 776 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 19775a4ec..79445a12d 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -496,7 +496,7 @@ fn infer_literals() {
496 26..30 '5f32': f32 496 26..30 '5f32': f32
497 36..40 '5f64': f64 497 36..40 '5f64': f64
498 46..53 '"hello"': &str 498 46..53 '"hello"': &str
499 59..67 'b"bytes"': &[u8; _] 499 59..67 'b"bytes"': &[u8; 5]
500 73..76 ''c'': char 500 73..76 ''c'': char
501 82..86 'b'b'': u8 501 82..86 'b'b'': u8
502 92..96 '3.14': f64 502 92..96 '3.14': f64
@@ -504,7 +504,7 @@ fn infer_literals() {
504 112..117 'false': bool 504 112..117 'false': bool
505 123..127 'true': bool 505 123..127 'true': bool
506 133..197 'r#" ... "#': &str 506 133..197 'r#" ... "#': &str
507 203..213 'br#"yolo"#': &[u8; _] 507 203..213 'br#"yolo"#': &[u8; 4]
508 "##]], 508 "##]],
509 ); 509 );
510} 510}
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 61dcbb399..c67ccd1a9 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -4,7 +4,7 @@ use ide_assists::utils::extract_trivial_expression;
4use itertools::Itertools; 4use itertools::Itertools;
5use syntax::{ 5use syntax::{
6 algo::non_trivia_sibling, 6 algo::non_trivia_sibling,
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken, IsString},
8 Direction, NodeOrToken, SourceFile, 8 Direction, NodeOrToken, SourceFile,
9 SyntaxKind::{self, USE_TREE, WHITESPACE}, 9 SyntaxKind::{self, USE_TREE, WHITESPACE},
10 SyntaxNode, SyntaxToken, TextRange, TextSize, T, 10 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index bc221d599..4269d339e 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -6,7 +6,7 @@ use either::Either;
6use hir::{InFile, Semantics}; 6use hir::{InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind}; 7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode}, 9 ast::{self, AstNode, IsString},
10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12 12
diff --git a/crates/ide_assists/src/handlers/raw_string.rs b/crates/ide_assists/src/handlers/raw_string.rs
index d0f1613f3..d98a55ae4 100644
--- a/crates/ide_assists/src/handlers/raw_string.rs
+++ b/crates/ide_assists/src/handlers/raw_string.rs
@@ -1,6 +1,6 @@
1use std::borrow::Cow; 1use std::borrow::Cow;
2 2
3use syntax::{ast, AstToken, TextRange, TextSize}; 3use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
4 4
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
6 6
diff --git a/crates/ide_assists/src/handlers/replace_string_with_char.rs b/crates/ide_assists/src/handlers/replace_string_with_char.rs
index 634b9c0b7..0800d291e 100644
--- a/crates/ide_assists/src/handlers/replace_string_with_char.rs
+++ b/crates/ide_assists/src/handlers/replace_string_with_char.rs
@@ -1,4 +1,4 @@
1use syntax::{ast, AstToken, SyntaxKind::STRING}; 1use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
2 2
3use crate::{AssistContext, AssistId, AssistKind, Assists}; 3use crate::{AssistContext, AssistId, AssistKind, Assists};
4 4
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 29d25a58a..4b1e1ccee 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -143,6 +143,30 @@ impl QuoteOffsets {
143 } 143 }
144} 144}
145 145
146pub 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
168impl IsString for ast::String {}
169
146impl ast::String { 170impl ast::String {
147 pub fn is_raw(&self) -> bool { 171 pub fn is_raw(&self) -> bool {
148 self.text().starts_with('r') 172 self.text().starts_with('r')
@@ -187,32 +211,49 @@ impl ast::String {
187 (false, false) => Some(Cow::Owned(buf)), 211 (false, false) => Some(Cow::Owned(buf)),
188 } 212 }
189 } 213 }
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 }
210} 214}
211 215
216impl IsString for ast::ByteString {}
217
212impl ast::ByteString { 218impl ast::ByteString {
213 pub fn is_raw(&self) -> bool { 219 pub fn is_raw(&self) -> bool {
214 self.text().starts_with("br") 220 self.text().starts_with("br")
215 } 221 }
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 }
216} 257}
217 258
218#[derive(Debug)] 259#[derive(Debug)]