Support length for ByteStrings

I am not confident that my added byte string parsing is right.
This commit is contained in:
Jade 2021-05-12 05:44:01 -07:00
parent 8b147624ff
commit 73023c0299
8 changed files with 85 additions and 33 deletions

View file

@ -1022,7 +1022,10 @@ impl From<ast::LiteralKind> for Literal {
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
Literal::Float(Default::default(), ty)
}
LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
LiteralKind::ByteString(bs) => {
let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
Literal::ByteString(text)
}
LiteralKind::String(_) => Literal::String(Default::default()),
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
LiteralKind::Bool(val) => Literal::Bool(val),

View file

@ -16,7 +16,7 @@ use stdx::always;
use syntax::ast::RangeOp;
use crate::{
autoderef, dummy_usize_const,
autoderef,
lower::lower_to_chalk_mutability,
mapping::from_chalk,
method_resolution, op,
@ -24,8 +24,9 @@ use crate::{
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
utils::{generics, Generics},
AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
AdtId, Binders, CallableDefId, ConcreteConst, ConstValue, FnPointer, FnSig, FnSubst,
InEnvironment, Interner, ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty,
TyBuilder, TyExt, TyKind,
};
use super::{
@ -758,11 +759,18 @@ impl<'a> InferenceContext<'a> {
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
.intern(&Interner)
}
Literal::ByteString(..) => {
Literal::ByteString(bs) => {
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
let array_type =
TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
let len = ConstData {
ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
value: ConstValue::Concrete(ConcreteConst {
interned: ConstScalar::Usize(bs.len() as u64),
}),
}
.intern(&Interner);
let array_type = TyKind::Array(byte_type, len).intern(&Interner);
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
}
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),

View file

@ -496,7 +496,7 @@ fn infer_literals() {
26..30 '5f32': f32
36..40 '5f64': f64
46..53 '"hello"': &str
59..67 'b"bytes"': &[u8; _]
59..67 'b"bytes"': &[u8; 5]
73..76 ''c'': char
82..86 'b'b'': u8
92..96 '3.14': f64
@ -504,7 +504,7 @@ fn infer_literals() {
112..117 'false': bool
123..127 'true': bool
133..197 'r#" ... "#': &str
203..213 'br#"yolo"#': &[u8; _]
203..213 'br#"yolo"#': &[u8; 4]
"##]],
);
}

View file

@ -4,7 +4,7 @@ use ide_assists::utils::extract_trivial_expression;
use itertools::Itertools;
use syntax::{
algo::non_trivia_sibling,
ast::{self, AstNode, AstToken},
ast::{self, AstNode, AstToken, IsString},
Direction, NodeOrToken, SourceFile,
SyntaxKind::{self, USE_TREE, WHITESPACE},
SyntaxNode, SyntaxToken, TextRange, TextSize, T,

View file

@ -6,7 +6,7 @@ use either::Either;
use hir::{InFile, Semantics};
use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
use syntax::{
ast::{self, AstNode},
ast::{self, AstNode, IsString},
AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
};

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use syntax::{ast, AstToken, TextRange, TextSize};
use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
use crate::{AssistContext, AssistId, AssistKind, Assists};

View file

@ -1,4 +1,4 @@
use syntax::{ast, AstToken, SyntaxKind::STRING};
use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
use crate::{AssistContext, AssistId, AssistKind, Assists};

View file

@ -143,6 +143,30 @@ impl QuoteOffsets {
}
}
pub trait IsString: AstToken {
fn quote_offsets(&self) -> Option<QuoteOffsets> {
let text = self.text();
let offsets = QuoteOffsets::new(text)?;
let o = self.syntax().text_range().start();
let offsets = QuoteOffsets {
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
contents: offsets.contents + o,
};
Some(offsets)
}
fn text_range_between_quotes(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.contents)
}
fn open_quote_text_range(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.quotes.0)
}
fn close_quote_text_range(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.quotes.1)
}
}
impl IsString for ast::String {}
impl ast::String {
pub fn is_raw(&self) -> bool {
self.text().starts_with('r')
@ -187,32 +211,49 @@ impl ast::String {
(false, false) => Some(Cow::Owned(buf)),
}
}
pub fn quote_offsets(&self) -> Option<QuoteOffsets> {
let text = self.text();
let offsets = QuoteOffsets::new(text)?;
let o = self.syntax().text_range().start();
let offsets = QuoteOffsets {
quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
contents: offsets.contents + o,
};
Some(offsets)
}
pub fn text_range_between_quotes(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.contents)
}
pub fn open_quote_text_range(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.quotes.0)
}
pub fn close_quote_text_range(&self) -> Option<TextRange> {
self.quote_offsets().map(|it| it.quotes.1)
}
}
impl IsString for ast::ByteString {}
impl ast::ByteString {
pub fn is_raw(&self) -> bool {
self.text().starts_with("br")
}
pub fn value(&self) -> Option<Cow<'_, [u8]>> {
if self.is_raw() {
let text = self.text();
let text =
&text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
return Some(Cow::Borrowed(text.as_bytes()));
}
let text = self.text();
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
let mut buf: Vec<u8> = Vec::new();
let mut text_iter = text.chars();
let mut has_error = false;
unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
unescaped_char,
buf.capacity() == 0,
) {
(Ok(c), false) => buf.push(c as u8),
(Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
(Ok(c), true) => {
buf.reserve_exact(text.len());
buf.extend_from_slice(&text[..char_range.start].as_bytes());
buf.push(c as u8);
}
(Err(_), _) => has_error = true,
});
match (has_error, buf.capacity() == 0) {
(true, _) => None,
(false, true) => Some(Cow::Borrowed(text.as_bytes())),
(false, false) => Some(Cow::Owned(buf)),
}
}
}
#[derive(Debug)]