From a6146d35b1615cf5fb908b29f34e58bfde3bf96d Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 10 Jan 2019 13:54:58 +0100 Subject: Implement type inference for literals (WIP) --- crates/ra_hir/src/expr.rs | 78 +++++++++++++++++++++++++++- crates/ra_hir/src/ty.rs | 33 +++++++++++- crates/ra_hir/src/ty/tests.rs | 20 +++++++ crates/ra_hir/src/ty/tests/data/basics.txt | 2 +- crates/ra_hir/src/ty/tests/data/literals.txt | 10 ++++ crates/ra_syntax/src/lib.rs | 5 ++ crates/ra_syntax/src/yellow.rs | 12 +++++ crates/ra_syntax/src/yellow/syntax_text.rs | 11 +++- 8 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/data/literals.txt (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index f0936e9f3..e07725d05 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -5,7 +5,10 @@ use rustc_hash::FxHashMap; use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use ra_db::{LocalSyntaxPtr, Cancelable}; -use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; +use ra_syntax::{ + SyntaxKind, + ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner} +}; use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; @@ -103,6 +106,19 @@ impl BodySyntaxMapping { } } +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Literal { + String(String), + ByteString(Vec), + Char(char), + Bool(bool), + Byte(u8), + Int, // this and float need additional information + Float, + Tuple { values: Vec }, + Array { values: Vec }, +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Expr { /// This is produced if syntax tree does not have a required expression piece. @@ -186,6 +202,7 @@ pub enum Expr { Tuple { exprs: Vec, }, + Literal(Literal), } pub use ra_syntax::ast::PrefixOp as UnaryOp; @@ -305,6 +322,20 @@ impl Expr { f(*expr); } } + Expr::Literal(l) => match l { + Literal::Array { values } | Literal::Tuple { values } => { + for &val in values { + f(val); + } + } + Literal::String(..) + | Literal::ByteString(..) + | Literal::Byte(..) + | Literal::Bool(..) + | Literal::Char(..) + | Literal::Int + | Literal::Float => {} + }, } } } @@ -633,13 +664,56 @@ impl ExprCollector { let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) } + ast::ExprKind::Literal(e) => { + let child = e.syntax().children().next(); + + if let Some(c) = child { + let lit = match c.kind() { + SyntaxKind::INT_NUMBER => Literal::Int, + SyntaxKind::FLOAT_NUMBER => Literal::Float, + SyntaxKind::STRING => { + // FIXME: this likely includes the " characters + let text = c.text().to_string(); + Literal::String(text) + } + SyntaxKind::ARRAY_EXPR => { + // TODO: recursively call to self + Literal::Array { values: vec![] } + } + SyntaxKind::PAREN_EXPR => { + // TODO: recursively call to self + Literal::Tuple { values: vec![] } + } + SyntaxKind::TRUE_KW => Literal::Bool(true), + SyntaxKind::FALSE_KW => Literal::Bool(false), + SyntaxKind::BYTE_STRING => { + // FIXME: this is completely incorrect for a variety + // of reasons, but at least it gives the right type + let bytes = c.text().to_string().into_bytes(); + Literal::ByteString(bytes) + } + SyntaxKind::CHAR => { + let character = c.text().char_at(1).unwrap_or('X'); + Literal::Char(character) + } + SyntaxKind::BYTE => { + let character = c.text().char_at(1).unwrap_or('X'); + Literal::Byte(character as u8) + } + _ => return self.alloc_expr(Expr::Missing, syntax_ptr), + }; + + self.alloc_expr(Expr::Literal(lit), syntax_ptr) + } else { + self.alloc_expr(Expr::Missing, syntax_ptr) + } + } // TODO implement HIR for these: ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::ExprKind::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), - ast::ExprKind::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), } } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index fa46ddfe9..0baa205a1 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -38,7 +38,7 @@ use crate::{ db::HirDatabase, type_ref::{TypeRef, Mutability}, name::KnownName, - expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement}, + expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement}, }; fn transpose(x: Cancelable>) -> Option> { @@ -1067,6 +1067,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::Tuple(Arc::from(ty_vec)) } + Expr::Literal(lit) => match lit { + Literal::Bool(..) => Ty::Bool, + Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared), + Literal::ByteString(..) => { + let byte_type = Arc::new(Ty::Uint(primitive::UintTy::U8)); + let slice_type = Arc::new(Ty::Slice(byte_type)); + Ty::Ref(slice_type, Mutability::Shared) + } + Literal::Byte(..) => Ty::Uint(primitive::UintTy::U8), + Literal::Char(..) => Ty::Char, + Literal::Tuple { values } => { + let mut inner_tys = Vec::new(); + for &expr in values { + let inner_ty = self.infer_expr(expr, &Expectation::none())?; + inner_tys.push(inner_ty); + } + Ty::Tuple(Arc::from(inner_tys)) + } + Literal::Array { values } => { + // simply take the type of the first element for now + let inner_ty = match values.get(0) { + Some(&expr) => self.infer_expr(expr, &Expectation::none())?, + None => Ty::Unknown, + }; + // TODO: we should return a Ty::Array when it becomes + // available + Ty::Slice(Arc::new(inner_ty)) + } + // TODO + Literal::Int | Literal::Float => Ty::Unknown, + }, }; // use a new type variable if we got Ty::Unknown here let ty = self.insert_type_vars_shallow(ty); diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 920188fc9..97d3d222f 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -132,6 +132,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { ); } +#[test] +fn infer_literals() { + check_inference( + r#" +fn test() { + 5i32; + "hello"; + b"bytes"; + 'c'; + b'b'; + 3.14; + 5000; + (0u32, -5isize); + [true, true, false] +} +"#, + "literals.txt", + ); +} + #[test] fn infer_backwards() { check_inference( diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt index ac7faae0a..e02947ba8 100644 --- a/crates/ra_hir/src/ty/tests/data/basics.txt +++ b/crates/ra_hir/src/ty/tests/data/basics.txt @@ -9,5 +9,5 @@ [69; 70) 'd': &str [76; 82) '1usize': [unknown] [88; 94) '1isize': [unknown] -[100; 106) '"test"': [unknown] +[100; 106) '"test"': &str [112; 118) '1.0f32': [unknown] diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt new file mode 100644 index 000000000..8b22eee31 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -0,0 +1,10 @@ +[11; 135) '{ ...lse] }': () +[17; 21) '5i32': [unknown] +[27; 34) '"hello"': &str +[40; 48) 'b"bytes"': &[u8] +[54; 57) ''c'': char +[63; 67) 'b'b'': u8 +[73; 77) '3.14': [unknown] +[83; 87) '5000': [unknown] +[93; 108) '(0u32, -5isize)': [unknown] +[114; 133) '[true,...false]': () diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 2a095817a..6181df9d7 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -59,24 +59,29 @@ impl SourceFile { assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); TreeArc::cast(root) } + pub fn parse(text: &str) -> TreeArc { let tokens = tokenize(&text); let (green, errors) = parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root); SourceFile::new(green, errors) } + pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc { self.incremental_reparse(edit) .unwrap_or_else(|| self.full_reparse(edit)) } + pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option> { reparsing::incremental_reparse(self.syntax(), edit, self.errors()) .map(|(green_node, errors)| SourceFile::new(green_node, errors)) } + fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc { let text = edit.apply(self.syntax().text().to_string()); SourceFile::parse(&text) } + pub fn errors(&self) -> Vec { let mut errors = self.syntax.root_data().clone(); errors.extend(validation::validate(self)); diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/yellow.rs index 93621d08a..03df00fc6 100644 --- a/crates/ra_syntax/src/yellow.rs +++ b/crates/ra_syntax/src/yellow.rs @@ -128,40 +128,52 @@ impl SyntaxNode { pub(crate) fn root_data(&self) -> &Vec { self.0.root_data() } + pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { self.0.replace_self(replacement) } + pub fn to_owned(&self) -> TreeArc { let ptr = TreeArc(self.0.to_owned()); TreeArc::cast(ptr) } + pub fn kind(&self) -> SyntaxKind { self.0.kind() } + pub fn range(&self) -> TextRange { self.0.range() } + pub fn text(&self) -> SyntaxText { SyntaxText::new(self) } + pub fn is_leaf(&self) -> bool { self.0.is_leaf() } + pub fn parent(&self) -> Option<&SyntaxNode> { self.0.parent().map(SyntaxNode::from_repr) } + pub fn first_child(&self) -> Option<&SyntaxNode> { self.0.first_child().map(SyntaxNode::from_repr) } + pub fn last_child(&self) -> Option<&SyntaxNode> { self.0.last_child().map(SyntaxNode::from_repr) } + pub fn next_sibling(&self) -> Option<&SyntaxNode> { self.0.next_sibling().map(SyntaxNode::from_repr) } + pub fn prev_sibling(&self) -> Option<&SyntaxNode> { self.0.prev_sibling().map(SyntaxNode::from_repr) } + pub fn children(&self) -> SyntaxNodeChildren { SyntaxNodeChildren(self.0.children()) } diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs index 08dbe57a2..378cd1b2e 100644 --- a/crates/ra_syntax/src/yellow/syntax_text.rs +++ b/crates/ra_syntax/src/yellow/syntax_text.rs @@ -15,6 +15,7 @@ impl<'a> SyntaxText<'a> { range: node.range(), } } + pub fn chunks(&self) -> impl Iterator { let range = self.range; self.node.descendants().filter_map(move |node| { @@ -24,15 +25,19 @@ impl<'a> SyntaxText<'a> { Some(&text[range]) }) } + pub fn push_to(&self, buf: &mut String) { self.chunks().for_each(|it| buf.push_str(it)); } + pub fn to_string(&self) -> String { self.chunks().collect() } + pub fn contains(&self, c: char) -> bool { self.chunks().any(|it| it.contains(c)) } + pub fn find(&self, c: char) -> Option { let mut acc: TextUnit = 0.into(); for chunk in self.chunks() { @@ -44,9 +49,11 @@ impl<'a> SyntaxText<'a> { } None } + pub fn len(&self) -> TextUnit { self.range.len() } + pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { let range = range.restrict(self.range).unwrap_or_else(|| { panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) @@ -56,8 +63,10 @@ impl<'a> SyntaxText<'a> { range, } } - pub fn char_at(&self, offset: TextUnit) -> Option { + + pub fn char_at(&self, offset: impl Into) -> Option { let mut start: TextUnit = 0.into(); + let offset = offset.into(); for chunk in self.chunks() { let end = start + TextUnit::of_str(chunk); if start <= offset && offset < end { -- cgit v1.2.3 From 5f5dc20d85dead5fbd51d163451f796255c9faea Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 10 Jan 2019 16:03:15 +0100 Subject: Try implementing integer type inference (WIP) --- crates/ra_hir/src/expr.rs | 58 +++++++++++++++++++++------ crates/ra_hir/src/ty.rs | 53 ++++++++++++------------ crates/ra_hir/src/ty/primitive.rs | 50 +++++++++++++++++++++++ crates/ra_hir/src/ty/tests/data/basics.txt | 4 +- crates/ra_hir/src/ty/tests/data/binary_op.txt | 2 +- crates/ra_hir/src/ty/tests/data/let.txt | 4 +- crates/ra_hir/src/ty/tests/data/literals.txt | 2 +- crates/ra_syntax/src/yellow.rs | 2 +- 8 files changed, 129 insertions(+), 46 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index e07725d05..bc8515836 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -11,6 +11,7 @@ use ra_syntax::{ }; use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; +use crate::ty::primitive::{UintTy, IntTy, FloatTy, UncertainIntTy, UncertainFloatTy}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ExprId(RawId); @@ -112,9 +113,8 @@ pub enum Literal { ByteString(Vec), Char(char), Bool(bool), - Byte(u8), - Int, // this and float need additional information - Float, + Int(u64, UncertainIntTy), + Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq Tuple { values: Vec }, Array { values: Vec }, } @@ -328,13 +328,7 @@ impl Expr { f(val); } } - Literal::String(..) - | Literal::ByteString(..) - | Literal::Byte(..) - | Literal::Bool(..) - | Literal::Char(..) - | Literal::Int - | Literal::Float => {} + _ => {} }, } } @@ -669,8 +663,43 @@ impl ExprCollector { if let Some(c) = child { let lit = match c.kind() { - SyntaxKind::INT_NUMBER => Literal::Int, - SyntaxKind::FLOAT_NUMBER => Literal::Float, + SyntaxKind::INT_NUMBER => { + let text = c.text().to_string(); + + // FIXME: don't do it like this. maybe use something like + // the IntTy::from_name functions + let ty = if text.ends_with("isize") { + UncertainIntTy::Signed(IntTy::Isize) + } else if text.ends_with("i128") { + UncertainIntTy::Signed(IntTy::I128) + } else if text.ends_with("i64") { + UncertainIntTy::Signed(IntTy::I64) + } else if text.ends_with("i32") { + UncertainIntTy::Signed(IntTy::I32) + } else if text.ends_with("i16") { + UncertainIntTy::Signed(IntTy::I16) + } else if text.ends_with("i8") { + UncertainIntTy::Signed(IntTy::I8) + } else if text.ends_with("usize") { + UncertainIntTy::Unsigned(UintTy::Usize) + } else if text.ends_with("u128") { + UncertainIntTy::Unsigned(UintTy::U128) + } else if text.ends_with("u64") { + UncertainIntTy::Unsigned(UintTy::U64) + } else if text.ends_with("u32") { + UncertainIntTy::Unsigned(UintTy::U32) + } else if text.ends_with("u16") { + UncertainIntTy::Unsigned(UintTy::U16) + } else if text.ends_with("u8") { + UncertainIntTy::Unsigned(UintTy::U8) + } else { + UncertainIntTy::Unknown + }; + + // TODO: actually parse integer + Literal::Int(0u64, ty) + } + SyntaxKind::FLOAT_NUMBER => Literal::Float(0, UncertainFloatTy::Unknown), SyntaxKind::STRING => { // FIXME: this likely includes the " characters let text = c.text().to_string(); @@ -698,7 +727,10 @@ impl ExprCollector { } SyntaxKind::BYTE => { let character = c.text().char_at(1).unwrap_or('X'); - Literal::Byte(character as u8) + Literal::Int( + character as u8 as u64, + UncertainIntTy::Unsigned(UintTy::U8), + ) } _ => return self.alloc_expr(Expr::Missing, syntax_ptr), }; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 0baa205a1..13a1c2907 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -14,7 +14,7 @@ //! rustc. mod autoderef; -mod primitive; +pub(crate) mod primitive; #[cfg(test)] mod tests; pub(crate) mod method_resolution; @@ -151,14 +151,13 @@ pub enum Ty { /// (a non-surrogate code point). Written as `char`. Char, - /// A primitive signed integer type. For example, `i32`. - Int(primitive::IntTy), - - /// A primitive unsigned integer type. For example, `u32`. - Uint(primitive::UintTy), + /// A primitive integer type. For example, `i32`. + Int(primitive::UncertainIntTy), + // /// A primitive unsigned integer type. For example, `u32`. + // Uint(primitive::UintTy), /// A primitive floating-point type. For example, `f64`. - Float(primitive::FloatTy), + Float(primitive::UncertainFloatTy), /// Structures, enumerations and unions. Adt { @@ -318,11 +317,9 @@ impl Ty { return Ok(Ty::Char); } else if let Some(KnownName::Str) = name.as_known_name() { return Ok(Ty::Str); - } else if let Some(int_ty) = primitive::IntTy::from_name(name) { + } else if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { return Ok(Ty::Int(int_ty)); - } else if let Some(uint_ty) = primitive::UintTy::from_name(name) { - return Ok(Ty::Uint(uint_ty)); - } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { + } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { return Ok(Ty::Float(float_ty)); } else if name.as_known_name() == Some(KnownName::SelfType) { return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); @@ -392,7 +389,6 @@ impl fmt::Display for Ty { Ty::Bool => write!(f, "bool"), Ty::Char => write!(f, "char"), Ty::Int(t) => write!(f, "{}", t.ty_to_string()), - Ty::Uint(t) => write!(f, "{}", t.ty_to_string()), Ty::Float(t) => write!(f, "{}", t.ty_to_string()), Ty::Str => write!(f, "str"), Ty::Slice(t) => write!(f, "[{}]", t), @@ -587,7 +583,7 @@ fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty { | BinaryOp::BitwiseAnd | BinaryOp::BitwiseOr | BinaryOp::BitwiseXor => match rhs_ty { - Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => rhs_ty, + Ty::Int(..) | Ty::Float(..) => rhs_ty, _ => Ty::Unknown, }, BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown, @@ -598,7 +594,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { match op { BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool, BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty { - Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty, + Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty, _ => Ty::Unknown, }, BinaryOp::LesserEqualTest @@ -625,7 +621,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { | BinaryOp::BitwiseAnd | BinaryOp::BitwiseOr | BinaryOp::BitwiseXor => match lhs_ty { - Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => lhs_ty, + Ty::Int(..) | Ty::Float(..) => lhs_ty, _ => Ty::Unknown, }, _ => Ty::Unknown, @@ -695,13 +691,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match (&*ty1, &*ty2) { (Ty::Unknown, ..) => true, (.., Ty::Unknown) => true, - (Ty::Bool, _) - | (Ty::Str, _) - | (Ty::Never, _) - | (Ty::Char, _) - | (Ty::Int(..), Ty::Int(..)) - | (Ty::Uint(..), Ty::Uint(..)) - | (Ty::Float(..), Ty::Float(..)) => ty1 == ty2, + (Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) { + (primitive::UncertainIntTy::Unknown, _) + | (_, primitive::UncertainIntTy::Unknown) => true, + _ => t1 == t2, + }, + (Ty::Float(t1), Ty::Float(t2)) => match (t1, t2) { + (primitive::UncertainFloatTy::Unknown, _) + | (_, primitive::UncertainFloatTy::Unknown) => true, + _ => t1 == t2, + }, + (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, ( Ty::Adt { def_id: def_id1, .. @@ -1071,11 +1071,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Literal::Bool(..) => Ty::Bool, Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared), Literal::ByteString(..) => { - let byte_type = Arc::new(Ty::Uint(primitive::UintTy::U8)); + let byte_type = Arc::new(Ty::Int(primitive::UncertainIntTy::Unsigned( + primitive::UintTy::U8, + ))); let slice_type = Arc::new(Ty::Slice(byte_type)); Ty::Ref(slice_type, Mutability::Shared) } - Literal::Byte(..) => Ty::Uint(primitive::UintTy::U8), Literal::Char(..) => Ty::Char, Literal::Tuple { values } => { let mut inner_tys = Vec::new(); @@ -1095,8 +1096,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // available Ty::Slice(Arc::new(inner_ty)) } - // TODO - Literal::Int | Literal::Float => Ty::Unknown, + Literal::Int(_v, ty) => Ty::Int(*ty), + Literal::Float(_v, ty) => Ty::Float(*ty), }, }; // use a new type variable if we got Ty::Unknown here diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 498d42d52..5741ca90d 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs @@ -2,6 +2,56 @@ use std::fmt; use crate::{Name, KnownName}; +#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] +pub enum UncertainIntTy { + Unknown, + Unsigned(UintTy), + Signed(IntTy), +} + +impl UncertainIntTy { + pub fn ty_to_string(&self) -> &'static str { + match *self { + UncertainIntTy::Unknown => "{integer}", + UncertainIntTy::Signed(ty) => ty.ty_to_string(), + UncertainIntTy::Unsigned(ty) => ty.ty_to_string(), + } + } + + pub fn from_name(name: &Name) -> Option { + if let Some(ty) = IntTy::from_name(name) { + Some(UncertainIntTy::Signed(ty)) + } else if let Some(ty) = UintTy::from_name(name) { + Some(UncertainIntTy::Unsigned(ty)) + } else { + None + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] +pub enum UncertainFloatTy { + Unknown, + Known(FloatTy), +} + +impl UncertainFloatTy { + pub fn ty_to_string(&self) -> &'static str { + match *self { + UncertainFloatTy::Unknown => "{float}", + UncertainFloatTy::Known(ty) => ty.ty_to_string(), + } + } + + pub fn from_name(name: &Name) -> Option { + if let Some(ty) = FloatTy::from_name(name) { + Some(UncertainFloatTy::Known(ty)) + } else { + None + } + } +} + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub enum IntTy { Isize, diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt index e02947ba8..4a3b69b7e 100644 --- a/crates/ra_hir/src/ty/tests/data/basics.txt +++ b/crates/ra_hir/src/ty/tests/data/basics.txt @@ -7,7 +7,7 @@ [55; 56) 'b': isize [62; 63) 'c': ! [69; 70) 'd': &str -[76; 82) '1usize': [unknown] -[88; 94) '1isize': [unknown] +[76; 82) '1usize': usize +[88; 94) '1isize': isize [100; 106) '"test"': &str [112; 118) '1.0f32': [unknown] diff --git a/crates/ra_hir/src/ty/tests/data/binary_op.txt b/crates/ra_hir/src/ty/tests/data/binary_op.txt index 8a515ac5e..7fdb8a900 100644 --- a/crates/ra_hir/src/ty/tests/data/binary_op.txt +++ b/crates/ra_hir/src/ty/tests/data/binary_op.txt @@ -16,7 +16,7 @@ [112; 113) 'y': bool [123; 134) 'minus_forty': isize [144; 152) '-40isize': isize -[145; 152) '40isize': [unknown] +[145; 152) '40isize': isize [162; 163) 'h': bool [166; 177) 'minus_forty': isize [166; 188) 'minus_...ONST_2': bool diff --git a/crates/ra_hir/src/ty/tests/data/let.txt b/crates/ra_hir/src/ty/tests/data/let.txt index 30f4a2cf5..8815dba41 100644 --- a/crates/ra_hir/src/ty/tests/data/let.txt +++ b/crates/ra_hir/src/ty/tests/data/let.txt @@ -1,6 +1,6 @@ [11; 71) '{ ...= b; }': () -[21; 22) 'a': [unknown] -[25; 31) '1isize': [unknown] +[21; 22) 'a': isize +[25; 31) '1isize': isize [41; 42) 'b': usize [52; 53) '1': usize [63; 64) 'c': usize diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index 8b22eee31..e139d57a8 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -1,5 +1,5 @@ [11; 135) '{ ...lse] }': () -[17; 21) '5i32': [unknown] +[17; 21) '5i32': i32 [27; 34) '"hello"': &str [40; 48) 'b"bytes"': &[u8] [54; 57) ''c'': char diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/yellow.rs index 03df00fc6..9b93945cc 100644 --- a/crates/ra_syntax/src/yellow.rs +++ b/crates/ra_syntax/src/yellow.rs @@ -128,7 +128,7 @@ impl SyntaxNode { pub(crate) fn root_data(&self) -> &Vec { self.0.root_data() } - + pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { self.0.replace_self(replacement) } -- cgit v1.2.3 From 1574715be5d3fc7e07160708810dcbc9c1b01733 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 10 Jan 2019 18:08:54 +0100 Subject: Use type variables to determine exact type for ambiguous numeric literals --- crates/ra_hir/src/expr.rs | 17 ++++++++++- crates/ra_hir/src/ty.rs | 45 ++++++++++++++++++++++++---- crates/ra_hir/src/ty/tests.rs | 1 + crates/ra_hir/src/ty/tests/data/basics.txt | 2 +- crates/ra_hir/src/ty/tests/data/literals.txt | 9 +++--- crates/ra_hir/src/ty/tests/data/struct.txt | 4 +-- 6 files changed, 64 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index bc8515836..2798937a6 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -699,7 +699,22 @@ impl ExprCollector { // TODO: actually parse integer Literal::Int(0u64, ty) } - SyntaxKind::FLOAT_NUMBER => Literal::Float(0, UncertainFloatTy::Unknown), + SyntaxKind::FLOAT_NUMBER => { + let text = c.text().to_string(); + + // FIXME: don't do it like this. maybe use something like + // the IntTy::from_name functions + let ty = if text.ends_with("f64") { + UncertainFloatTy::Known(FloatTy::F64) + } else if text.ends_with("f32") { + UncertainFloatTy::Known(FloatTy::F32) + } else { + UncertainFloatTy::Unknown + }; + + // TODO: actually parse value + Literal::Float(0, ty) + } SyntaxKind::STRING => { // FIXME: this likely includes the " characters let text = c.text().to_string(); diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 13a1c2907..b4b338874 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -114,6 +114,8 @@ impl UnifyValue for TypeVarValue { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum InferTy { TypeVar(TypeVarId), + IntVar(TypeVarId), + FloatVar(TypeVarId), } /// When inferring an expression, we propagate downward whatever type hint we @@ -718,12 +720,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .iter() .zip(ts2.iter()) .all(|(t1, t2)| self.unify(t1, t2)), - (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => { + (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) + | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) + | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => { // both type vars are unknown since we tried to resolve them self.var_unification_table.union(*tv1, *tv2); true } - (Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => { + (Ty::Infer(InferTy::TypeVar(tv)), other) + | (other, Ty::Infer(InferTy::TypeVar(tv))) + | (Ty::Infer(InferTy::IntVar(tv)), other) + | (other, Ty::Infer(InferTy::IntVar(tv))) + | (Ty::Infer(InferTy::FloatVar(tv)), other) + | (other, Ty::Infer(InferTy::FloatVar(tv))) => { // the type var is unknown since we tried to resolve it self.var_unification_table .union_value(*tv, TypeVarValue::Known(other.clone())); @@ -739,10 +748,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { )) } + fn new_integer_var(&mut self) -> Ty { + Ty::Infer(InferTy::IntVar( + self.var_unification_table.new_key(TypeVarValue::Unknown), + )) + } + + fn new_float_var(&mut self) -> Ty { + Ty::Infer(InferTy::FloatVar( + self.var_unification_table.new_key(TypeVarValue::Unknown), + )) + } + /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { Ty::Unknown => self.new_type_var(), + Ty::Int(primitive::UncertainIntTy::Unknown) => self.new_integer_var(), + Ty::Float(primitive::UncertainFloatTy::Unknown) => self.new_float_var(), _ => ty, } } @@ -757,12 +780,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// known type. fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { ty.fold(&mut |ty| match ty { - Ty::Infer(InferTy::TypeVar(tv)) => { + Ty::Infer(InferTy::TypeVar(tv)) + | Ty::Infer(InferTy::IntVar(tv)) + | Ty::Infer(InferTy::FloatVar(tv)) => { if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { // known_ty may contain other variables that are known by now self.resolve_ty_as_possible(known_ty.clone()) } else { - Ty::Infer(InferTy::TypeVar(tv)) + ty } } _ => ty, @@ -790,12 +815,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// replaced by Ty::Unknown. fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { ty.fold(&mut |ty| match ty { - Ty::Infer(InferTy::TypeVar(tv)) => { + Ty::Infer(i) => { + let tv = match i { + InferTy::TypeVar(tv) | InferTy::IntVar(tv) | InferTy::FloatVar(tv) => tv, + }; + if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { // known_ty may contain other variables that are known by now self.resolve_ty_completely(known_ty.clone()) } else { - Ty::Unknown + match i { + InferTy::TypeVar(..) => Ty::Unknown, + InferTy::IntVar(..) => Ty::Int(primitive::UncertainIntTy::Unknown), + InferTy::FloatVar(..) => Ty::Float(primitive::UncertainFloatTy::Unknown), + } } } _ => ty, diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 97d3d222f..0c43415a6 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -145,6 +145,7 @@ fn test() { 3.14; 5000; (0u32, -5isize); + false; [true, true, false] } "#, diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt index 4a3b69b7e..e65fe07aa 100644 --- a/crates/ra_hir/src/ty/tests/data/basics.txt +++ b/crates/ra_hir/src/ty/tests/data/basics.txt @@ -10,4 +10,4 @@ [76; 82) '1usize': usize [88; 94) '1isize': isize [100; 106) '"test"': &str -[112; 118) '1.0f32': [unknown] +[112; 118) '1.0f32': f32 diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index e139d57a8..df435edd7 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -1,10 +1,11 @@ -[11; 135) '{ ...lse] }': () +[11; 146) '{ ...lse] }': () [17; 21) '5i32': i32 [27; 34) '"hello"': &str [40; 48) 'b"bytes"': &[u8] [54; 57) ''c'': char [63; 67) 'b'b'': u8 -[73; 77) '3.14': [unknown] -[83; 87) '5000': [unknown] +[73; 77) '3.14': {float} +[83; 87) '5000': {integer} [93; 108) '(0u32, -5isize)': [unknown] -[114; 133) '[true,...false]': () +[114; 119) 'false': bool +[125; 144) '[true,...false]': () diff --git a/crates/ra_hir/src/ty/tests/data/struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt index 7b324c82f..dcdf61363 100644 --- a/crates/ra_hir/src/ty/tests/data/struct.txt +++ b/crates/ra_hir/src/ty/tests/data/struct.txt @@ -2,14 +2,14 @@ [82; 83) 'c': [unknown] [86; 87) 'C': [unknown] [86; 90) 'C(1)': [unknown] -[88; 89) '1': [unknown] +[88; 89) '1': {integer} [96; 97) 'B': [unknown] [107; 108) 'a': A [114; 133) 'A { b:...C(1) }': A [121; 122) 'B': B [127; 128) 'C': [unknown] [127; 131) 'C(1)': C -[129; 130) '1': [unknown] +[129; 130) '1': {integer} [139; 140) 'a': A [139; 142) 'a.b': B [148; 149) 'a': A -- cgit v1.2.3 From 81bc8e4973fefd0ff31d08206c374fb58aa8b6e0 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Fri, 11 Jan 2019 09:47:31 +0100 Subject: don't try to treat arrays and tuples as literals --- crates/ra_hir/src/expr.rs | 19 +---------- crates/ra_hir/src/ty.rs | 49 ++++++++++++---------------- crates/ra_hir/src/ty/tests.rs | 2 -- crates/ra_hir/src/ty/tests/data/literals.txt | 10 +++--- crates/ra_hir/src/ty/tests/data/struct.txt | 4 +-- 5 files changed, 27 insertions(+), 57 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 2798937a6..52af2af45 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -115,8 +115,6 @@ pub enum Literal { Bool(bool), Int(u64, UncertainIntTy), Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq - Tuple { values: Vec }, - Array { values: Vec }, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -322,14 +320,7 @@ impl Expr { f(*expr); } } - Expr::Literal(l) => match l { - Literal::Array { values } | Literal::Tuple { values } => { - for &val in values { - f(val); - } - } - _ => {} - }, + Expr::Literal(_) => {} } } } @@ -720,14 +711,6 @@ impl ExprCollector { let text = c.text().to_string(); Literal::String(text) } - SyntaxKind::ARRAY_EXPR => { - // TODO: recursively call to self - Literal::Array { values: vec![] } - } - SyntaxKind::PAREN_EXPR => { - // TODO: recursively call to self - Literal::Tuple { values: vec![] } - } SyntaxKind::TRUE_KW => Literal::Bool(true), SyntaxKind::FALSE_KW => Literal::Bool(false), SyntaxKind::BYTE_STRING => { diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index b4b338874..de5ec5b46 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -107,9 +107,9 @@ impl UnifyValue for TypeVarValue { } } -/// The kinds of placeholders we need during type inference. Currently, we only -/// have type variables; in the future, we will probably also need int and float -/// variables, for inference of literal values (e.g. `100` could be one of +/// The kinds of placeholders we need during type inference. There's seperate +/// values for general types, and for integer and float variables. The latter +/// two are used for inference of literal values (e.g. `100` could be one of /// several integer types). #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum InferTy { @@ -118,6 +118,20 @@ pub enum InferTy { FloatVar(TypeVarId), } +impl InferTy { + fn fallback_value(self) -> Ty { + match self { + InferTy::TypeVar(..) => Ty::Unknown, + InferTy::IntVar(..) => { + Ty::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32)) + } + InferTy::FloatVar(..) => { + Ty::Float(primitive::UncertainFloatTy::Known(primitive::FloatTy::F64)) + } + } + } +} + /// When inferring an expression, we propagate downward whatever type hint we /// are able in the form of an `Expectation`. #[derive(Clone, PartialEq, Eq, Debug)] @@ -156,8 +170,6 @@ pub enum Ty { /// A primitive integer type. For example, `i32`. Int(primitive::UncertainIntTy), - // /// A primitive unsigned integer type. For example, `u32`. - // Uint(primitive::UintTy), /// A primitive floating-point type. For example, `f64`. Float(primitive::UncertainFloatTy), @@ -199,8 +211,9 @@ pub enum Ty { // above function pointer type. Once we implement generics, we will probably // need this as well. - // A trait, defined with `dyn trait`. + // A trait, defined with `dyn Trait`. // Dynamic(), + // The anonymous type of a closure. Used to represent the type of // `|a| a`. // Closure(DefId, ClosureSubsts<'tcx>), @@ -824,11 +837,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // known_ty may contain other variables that are known by now self.resolve_ty_completely(known_ty.clone()) } else { - match i { - InferTy::TypeVar(..) => Ty::Unknown, - InferTy::IntVar(..) => Ty::Int(primitive::UncertainIntTy::Unknown), - InferTy::FloatVar(..) => Ty::Float(primitive::UncertainFloatTy::Unknown), - } + i.fallback_value() } } _ => ty, @@ -1111,24 +1120,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::Ref(slice_type, Mutability::Shared) } Literal::Char(..) => Ty::Char, - Literal::Tuple { values } => { - let mut inner_tys = Vec::new(); - for &expr in values { - let inner_ty = self.infer_expr(expr, &Expectation::none())?; - inner_tys.push(inner_ty); - } - Ty::Tuple(Arc::from(inner_tys)) - } - Literal::Array { values } => { - // simply take the type of the first element for now - let inner_ty = match values.get(0) { - Some(&expr) => self.infer_expr(expr, &Expectation::none())?, - None => Ty::Unknown, - }; - // TODO: we should return a Ty::Array when it becomes - // available - Ty::Slice(Arc::new(inner_ty)) - } Literal::Int(_v, ty) => Ty::Int(*ty), Literal::Float(_v, ty) => Ty::Float(*ty), }, diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 0c43415a6..53ea99874 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -144,9 +144,7 @@ fn test() { b'b'; 3.14; 5000; - (0u32, -5isize); false; - [true, true, false] } "#, "literals.txt", diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index df435edd7..8d6079c98 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -1,11 +1,9 @@ -[11; 146) '{ ...lse] }': () +[11; 101) '{ ...lse; }': () [17; 21) '5i32': i32 [27; 34) '"hello"': &str [40; 48) 'b"bytes"': &[u8] [54; 57) ''c'': char [63; 67) 'b'b'': u8 -[73; 77) '3.14': {float} -[83; 87) '5000': {integer} -[93; 108) '(0u32, -5isize)': [unknown] -[114; 119) 'false': bool -[125; 144) '[true,...false]': () +[73; 77) '3.14': f64 +[83; 87) '5000': i32 +[93; 98) 'false': bool diff --git a/crates/ra_hir/src/ty/tests/data/struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt index dcdf61363..be9e12d02 100644 --- a/crates/ra_hir/src/ty/tests/data/struct.txt +++ b/crates/ra_hir/src/ty/tests/data/struct.txt @@ -2,14 +2,14 @@ [82; 83) 'c': [unknown] [86; 87) 'C': [unknown] [86; 90) 'C(1)': [unknown] -[88; 89) '1': {integer} +[88; 89) '1': i32 [96; 97) 'B': [unknown] [107; 108) 'a': A [114; 133) 'A { b:...C(1) }': A [121; 122) 'B': B [127; 128) 'C': [unknown] [127; 131) 'C(1)': C -[129; 130) '1': {integer} +[129; 130) '1': i32 [139; 140) 'a': A [139; 142) 'a.b': B [148; 149) 'a': A -- cgit v1.2.3 From 606d66a714bb8fe07f35a6af83d04ab576b9a0e1 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Fri, 11 Jan 2019 11:27:07 +0100 Subject: Start moving literal interpretation to the AST (WIP) --- crates/ra_hir/src/expr.rs | 7 +- crates/ra_syntax/src/ast/generated.rs | 114 ++++++++++++++++++++++++- crates/ra_syntax/src/grammar.ron | 18 +++- crates/ra_syntax/src/syntax_kinds/generated.rs | 2 + 4 files changed, 131 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 52af2af45..3f2689781 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -649,10 +649,9 @@ impl ExprCollector { let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) } - ast::ExprKind::Literal(e) => { - let child = e.syntax().children().next(); - - if let Some(c) = child { + ast::ExprKind::LiteralExpr(e) => { + if let Some(child) = e.literal() { + let c = child.syntax(); let lit = match c.kind() { SyntaxKind::INT_NUMBER => { let text = c.text().to_string(); diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 94842a514..442659aee 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -664,7 +664,7 @@ pub enum ExprKind<'a> { PrefixExpr(&'a PrefixExpr), RangeExpr(&'a RangeExpr), BinExpr(&'a BinExpr), - Literal(&'a Literal), + LiteralExpr(&'a LiteralExpr), } impl AstNode for Expr { @@ -696,7 +696,7 @@ impl AstNode for Expr { | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR - | LITERAL => Some(Expr::from_repr(syntax.into_repr())), + | LITERAL_EXPR => Some(Expr::from_repr(syntax.into_repr())), _ => None, } } @@ -733,7 +733,7 @@ impl Expr { PREFIX_EXPR => ExprKind::PrefixExpr(PrefixExpr::cast(&self.syntax).unwrap()), RANGE_EXPR => ExprKind::RangeExpr(RangeExpr::cast(&self.syntax).unwrap()), BIN_EXPR => ExprKind::BinExpr(BinExpr::cast(&self.syntax).unwrap()), - LITERAL => ExprKind::Literal(Literal::cast(&self.syntax).unwrap()), + LITERAL_EXPR => ExprKind::LiteralExpr(LiteralExpr::cast(&self.syntax).unwrap()), _ => unreachable!(), } } @@ -849,6 +849,31 @@ impl AstNode for FieldPatList { impl FieldPatList {} +// FloatNumber +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct FloatNumber { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for FloatNumber { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for FloatNumber { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for FloatNumber {} +impl FloatNumber {} + // FnDef #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1130,6 +1155,31 @@ impl AstNode for IndexExpr { impl IndexExpr {} +// IntNumber +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct IntNumber { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for IntNumber { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for IntNumber { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for IntNumber {} +impl IntNumber {} + // ItemList #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1315,10 +1365,25 @@ unsafe impl TransparentNewType for Literal { type Repr = rowan::SyntaxNode; } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LiteralKind<'a> { + String(&'a String), + ByteString(&'a ByteString), + Char(&'a Char), + Byte(&'a Byte), + IntNumber(&'a IntNumber), + FloatNumber(&'a FloatNumber), +} + impl AstNode for Literal { fn cast(syntax: &SyntaxNode) -> Option<&Self> { match syntax.kind() { - LITERAL => Some(Literal::from_repr(syntax.into_repr())), + | STRING + | BYTE_STRING + | CHAR + | BYTE + | INT_NUMBER + | FLOAT_NUMBER => Some(Literal::from_repr(syntax.into_repr())), _ => None, } } @@ -1326,9 +1391,50 @@ impl AstNode for Literal { fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } } +impl Literal { + pub fn kind(&self) -> LiteralKind { + match self.syntax.kind() { + STRING => LiteralKind::String(String::cast(&self.syntax).unwrap()), + BYTE_STRING => LiteralKind::ByteString(ByteString::cast(&self.syntax).unwrap()), + CHAR => LiteralKind::Char(Char::cast(&self.syntax).unwrap()), + BYTE => LiteralKind::Byte(Byte::cast(&self.syntax).unwrap()), + INT_NUMBER => LiteralKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), + FLOAT_NUMBER => LiteralKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), + _ => unreachable!(), + } + } +} impl Literal {} +// LiteralExpr +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct LiteralExpr { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for LiteralExpr { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for LiteralExpr { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + LITERAL_EXPR => Some(LiteralExpr::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } +} + + +impl LiteralExpr { + pub fn literal(&self) -> Option<&Literal> { + super::child_opt(self) + } +} + // LoopExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index dfd88bd10..49b297696 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -215,6 +215,7 @@ Grammar( "PATH", "PATH_SEGMENT", "LITERAL", + "LITERAL_EXPR", "ALIAS", "VISIBILITY", "WHERE_CLAUSE", @@ -426,11 +427,24 @@ Grammar( "PrefixExpr": (options: ["Expr"]), "RangeExpr": (), "BinExpr": (), + + "IntNumber": ( traits: ["AstToken"] ), + "FloatNumber": ( traits: ["AstToken"] ), "String": ( traits: ["AstToken"] ), "Byte": ( traits: ["AstToken"] ), "ByteString": ( traits: ["AstToken"] ), "Char": ( traits: ["AstToken"] ), - "Literal": (), + "Literal": ( + enum: [ + "String", + "ByteString", + "Char", + "Byte", + "IntNumber", + "FloatNumber", + ] + ), + "LiteralExpr": (options: ["Literal"]), "Expr": ( enum: [ @@ -460,7 +474,7 @@ Grammar( "PrefixExpr", "RangeExpr", "BinExpr", - "Literal", + "LiteralExpr", ], ), diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs index 830fac9f4..46795d6e9 100644 --- a/crates/ra_syntax/src/syntax_kinds/generated.rs +++ b/crates/ra_syntax/src/syntax_kinds/generated.rs @@ -205,6 +205,7 @@ pub enum SyntaxKind { PATH, PATH_SEGMENT, LITERAL, + LITERAL_EXPR, ALIAS, VISIBILITY, WHERE_CLAUSE, @@ -467,6 +468,7 @@ impl SyntaxKind { PATH => &SyntaxInfo { name: "PATH" }, PATH_SEGMENT => &SyntaxInfo { name: "PATH_SEGMENT" }, LITERAL => &SyntaxInfo { name: "LITERAL" }, + LITERAL_EXPR => &SyntaxInfo { name: "LITERAL_EXPR" }, ALIAS => &SyntaxInfo { name: "ALIAS" }, VISIBILITY => &SyntaxInfo { name: "VISIBILITY" }, WHERE_CLAUSE => &SyntaxInfo { name: "WHERE_CLAUSE" }, -- cgit v1.2.3 From a9a6a50c759302e8a8d59bf6c53c72ec804324b3 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 14 Jan 2019 19:30:21 +0100 Subject: Fixup tests --- crates/ra_hir/src/expr.rs | 141 ++++++++++--------------- crates/ra_hir/src/name.rs | 2 +- crates/ra_hir/src/ty.rs | 46 ++++---- crates/ra_hir/src/ty/tests.rs | 5 +- crates/ra_hir/src/ty/tests/data/binary_op.txt | 86 +++++++-------- crates/ra_hir/src/ty/tests/data/literals.txt | 3 +- crates/ra_hir/src/ty/tests/data/tuple.txt | 18 ++-- crates/ra_syntax/src/ast.rs | 46 ++++++++ crates/ra_syntax/src/ast/generated.rs | 132 ++++++++++++++++------- crates/ra_syntax/src/grammar.ron | 11 +- crates/ra_syntax/src/lib.rs | 2 +- crates/ra_syntax/src/syntax_kinds/generated.rs | 2 - 12 files changed, 283 insertions(+), 211 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 3f2689781..2f3432870 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -6,12 +6,11 @@ use rustc_hash::FxHashMap; use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use ra_db::{LocalSyntaxPtr, Cancelable}; use ra_syntax::{ - SyntaxKind, - ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner} + ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor} }; use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; -use crate::ty::primitive::{UintTy, IntTy, FloatTy, UncertainIntTy, UncertainFloatTy}; +use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ExprId(RawId); @@ -649,93 +648,59 @@ impl ExprCollector { let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) } - ast::ExprKind::LiteralExpr(e) => { - if let Some(child) = e.literal() { - let c = child.syntax(); - let lit = match c.kind() { - SyntaxKind::INT_NUMBER => { - let text = c.text().to_string(); - - // FIXME: don't do it like this. maybe use something like - // the IntTy::from_name functions - let ty = if text.ends_with("isize") { - UncertainIntTy::Signed(IntTy::Isize) - } else if text.ends_with("i128") { - UncertainIntTy::Signed(IntTy::I128) - } else if text.ends_with("i64") { - UncertainIntTy::Signed(IntTy::I64) - } else if text.ends_with("i32") { - UncertainIntTy::Signed(IntTy::I32) - } else if text.ends_with("i16") { - UncertainIntTy::Signed(IntTy::I16) - } else if text.ends_with("i8") { - UncertainIntTy::Signed(IntTy::I8) - } else if text.ends_with("usize") { - UncertainIntTy::Unsigned(UintTy::Usize) - } else if text.ends_with("u128") { - UncertainIntTy::Unsigned(UintTy::U128) - } else if text.ends_with("u64") { - UncertainIntTy::Unsigned(UintTy::U64) - } else if text.ends_with("u32") { - UncertainIntTy::Unsigned(UintTy::U32) - } else if text.ends_with("u16") { - UncertainIntTy::Unsigned(UintTy::U16) - } else if text.ends_with("u8") { - UncertainIntTy::Unsigned(UintTy::U8) - } else { - UncertainIntTy::Unknown - }; - - // TODO: actually parse integer - Literal::Int(0u64, ty) - } - SyntaxKind::FLOAT_NUMBER => { - let text = c.text().to_string(); - - // FIXME: don't do it like this. maybe use something like - // the IntTy::from_name functions - let ty = if text.ends_with("f64") { - UncertainFloatTy::Known(FloatTy::F64) - } else if text.ends_with("f32") { - UncertainFloatTy::Known(FloatTy::F32) - } else { - UncertainFloatTy::Unknown - }; - - // TODO: actually parse value - Literal::Float(0, ty) - } - SyntaxKind::STRING => { - // FIXME: this likely includes the " characters - let text = c.text().to_string(); - Literal::String(text) - } - SyntaxKind::TRUE_KW => Literal::Bool(true), - SyntaxKind::FALSE_KW => Literal::Bool(false), - SyntaxKind::BYTE_STRING => { - // FIXME: this is completely incorrect for a variety - // of reasons, but at least it gives the right type - let bytes = c.text().to_string().into_bytes(); - Literal::ByteString(bytes) - } - SyntaxKind::CHAR => { - let character = c.text().char_at(1).unwrap_or('X'); - Literal::Char(character) + ast::ExprKind::Literal(e) => { + let child = if let Some(child) = e.literal_expr() { + child + } else { + return self.alloc_expr(Expr::Missing, syntax_ptr); + }; + let c = child.syntax(); + + let lit = match child.flavor() { + LiteralFlavor::IntNumber { suffix } => { + let known_name = suffix + .map(|s| Name::new(s)) + .and_then(|name| UncertainIntTy::from_name(&name)); + + if let Some(kn) = known_name { + Literal::Int(0u64, kn) + } else { + Literal::Int(0u64, UncertainIntTy::Unknown) } - SyntaxKind::BYTE => { - let character = c.text().char_at(1).unwrap_or('X'); - Literal::Int( - character as u8 as u64, - UncertainIntTy::Unsigned(UintTy::U8), - ) + } + LiteralFlavor::FloatNumber { suffix } => { + let known_name = suffix + .map(|s| Name::new(s)) + .and_then(|name| UncertainFloatTy::from_name(&name)); + + if let Some(kn) = known_name { + Literal::Float(0u64, kn) + } else { + Literal::Float(0u64, UncertainFloatTy::Unknown) } - _ => return self.alloc_expr(Expr::Missing, syntax_ptr), - }; - - self.alloc_expr(Expr::Literal(lit), syntax_ptr) - } else { - self.alloc_expr(Expr::Missing, syntax_ptr) - } + } + LiteralFlavor::ByteString => { + // FIXME: this is completely incorrect for a variety + // of reasons, but at least it gives the right type + let bytes = c.text().to_string().into_bytes(); + Literal::ByteString(bytes) + } + LiteralFlavor::String => { + // FIXME: this likely includes the " characters + let text = c.text().to_string(); + Literal::String(text) + } + LiteralFlavor::Byte => { + let character = c.text().char_at(1).unwrap_or('X'); + Literal::Int(character as u8 as u64, UncertainIntTy::Unsigned(UintTy::U8)) + } + LiteralFlavor::Bool => Literal::Bool(true), + LiteralFlavor::Char => { + let character = c.text().char_at(1).unwrap_or('X'); + Literal::Char(character) + } + }; + self.alloc_expr(Expr::Literal(lit), syntax_ptr) } // TODO implement HIR for these: diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index d9683549c..8d786d2ac 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -23,7 +23,7 @@ impl fmt::Debug for Name { } impl Name { - fn new(text: SmolStr) -> Name { + pub(crate) fn new(text: SmolStr) -> Name { Name { text } } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index de5ec5b46..b6577ee5e 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -111,7 +111,7 @@ impl UnifyValue for TypeVarValue { /// values for general types, and for integer and float variables. The latter /// two are used for inference of literal values (e.g. `100` could be one of /// several integer types). -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum InferTy { TypeVar(TypeVarId), IntVar(TypeVarId), @@ -119,6 +119,12 @@ pub enum InferTy { } impl InferTy { + fn to_inner(self) -> TypeVarId { + match self { + InferTy::TypeVar(ty) | InferTy::IntVar(ty) | InferTy::FloatVar(ty) => ty, + } + } + fn fallback_value(self) -> Ty { match self { InferTy::TypeVar(..) => Ty::Unknown, @@ -326,18 +332,19 @@ impl Ty { path: &Path, ) -> Cancelable { if let Some(name) = path.as_ident() { - if let Some(KnownName::Bool) = name.as_known_name() { - return Ok(Ty::Bool); - } else if let Some(KnownName::Char) = name.as_known_name() { - return Ok(Ty::Char); - } else if let Some(KnownName::Str) = name.as_known_name() { - return Ok(Ty::Str); - } else if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { + if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { return Ok(Ty::Int(int_ty)); } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { return Ok(Ty::Float(float_ty)); } else if name.as_known_name() == Some(KnownName::SelfType) { return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); + } else if let Some(known) = name.as_known_name() { + match known { + KnownName::Bool => return Ok(Ty::Bool), + KnownName::Char => return Ok(Ty::Char), + KnownName::Str => return Ok(Ty::Str), + _ => {} + } } } @@ -793,10 +800,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// known type. fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { ty.fold(&mut |ty| match ty { - Ty::Infer(InferTy::TypeVar(tv)) - | Ty::Infer(InferTy::IntVar(tv)) - | Ty::Infer(InferTy::FloatVar(tv)) => { - if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { // known_ty may contain other variables that are known by now self.resolve_ty_as_possible(known_ty.clone()) } else { @@ -811,8 +817,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// otherwise, return ty. fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { match ty { - Ty::Infer(InferTy::TypeVar(tv)) => { - match self.var_unification_table.probe_value(*tv).known() { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + match self.var_unification_table.probe_value(inner).known() { Some(known_ty) => { // The known_ty can't be a type var itself Cow::Owned(known_ty.clone()) @@ -828,16 +835,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// replaced by Ty::Unknown. fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { ty.fold(&mut |ty| match ty { - Ty::Infer(i) => { - let tv = match i { - InferTy::TypeVar(tv) | InferTy::IntVar(tv) | InferTy::FloatVar(tv) => tv, - }; - - if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { // known_ty may contain other variables that are known by now self.resolve_ty_completely(known_ty.clone()) } else { - i.fallback_value() + tv.fallback_value() } } _ => ty, diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 53ea99874..cbdb2a4b7 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -145,6 +145,7 @@ fn test() { 3.14; 5000; false; + true; } "#, "literals.txt", @@ -199,7 +200,7 @@ fn f(x: bool) -> i32 { 0i32 } -fn test() { +fn test() -> bool { let x = a && b; let y = true || false; let z = x == y; @@ -296,8 +297,6 @@ fn test(x: &str, y: isize) { let b = (a, x); let c = (y, x); let d = (c, x); - - // we have not infered these case yet. let e = (1, "e"); let f = (e, "d"); } diff --git a/crates/ra_hir/src/ty/tests/data/binary_op.txt b/crates/ra_hir/src/ty/tests/data/binary_op.txt index 7fdb8a900..58a727691 100644 --- a/crates/ra_hir/src/ty/tests/data/binary_op.txt +++ b/crates/ra_hir/src/ty/tests/data/binary_op.txt @@ -1,46 +1,46 @@ [6; 7) 'x': bool [22; 34) '{ 0i32 }': i32 [28; 32) '0i32': i32 -[46; 342) '{ ... < 3 }': bool -[56; 57) 'x': bool -[60; 61) 'a': bool -[60; 66) 'a && b': bool -[65; 66) 'b': bool -[76; 77) 'y': bool -[80; 84) 'true': bool -[80; 93) 'true || false': bool -[88; 93) 'false': bool -[103; 104) 'z': bool -[107; 108) 'x': bool -[107; 113) 'x == y': bool -[112; 113) 'y': bool -[123; 134) 'minus_forty': isize -[144; 152) '-40isize': isize -[145; 152) '40isize': isize -[162; 163) 'h': bool -[166; 177) 'minus_forty': isize -[166; 188) 'minus_...ONST_2': bool -[181; 188) 'CONST_2': isize -[198; 199) 'c': i32 -[202; 203) 'f': fn(bool) -> i32 -[202; 211) 'f(z || y)': i32 -[202; 215) 'f(z || y) + 5': i32 -[204; 205) 'z': bool -[204; 210) 'z || y': bool -[209; 210) 'y': bool -[214; 215) '5': i32 -[225; 226) 'd': [unknown] -[229; 230) 'b': [unknown] -[240; 241) 'g': () -[244; 255) 'minus_forty': isize -[244; 260) 'minus_...y ^= i': () -[259; 260) 'i': isize -[270; 273) 'ten': usize -[283; 285) '10': usize -[295; 308) 'ten_is_eleven': bool -[311; 314) 'ten': usize -[311; 326) 'ten == some_num': bool -[318; 326) 'some_num': usize -[333; 336) 'ten': usize -[333; 340) 'ten < 3': bool -[339; 340) '3': usize +[54; 350) '{ ... < 3 }': bool +[64; 65) 'x': bool +[68; 69) 'a': bool +[68; 74) 'a && b': bool +[73; 74) 'b': bool +[84; 85) 'y': bool +[88; 92) 'true': bool +[88; 101) 'true || false': bool +[96; 101) 'false': bool +[111; 112) 'z': bool +[115; 116) 'x': bool +[115; 121) 'x == y': bool +[120; 121) 'y': bool +[131; 142) 'minus_forty': isize +[152; 160) '-40isize': isize +[153; 160) '40isize': isize +[170; 171) 'h': bool +[174; 185) 'minus_forty': isize +[174; 196) 'minus_...ONST_2': bool +[189; 196) 'CONST_2': isize +[206; 207) 'c': i32 +[210; 211) 'f': fn(bool) -> i32 +[210; 219) 'f(z || y)': i32 +[210; 223) 'f(z || y) + 5': i32 +[212; 213) 'z': bool +[212; 218) 'z || y': bool +[217; 218) 'y': bool +[222; 223) '5': i32 +[233; 234) 'd': [unknown] +[237; 238) 'b': [unknown] +[248; 249) 'g': () +[252; 263) 'minus_forty': isize +[252; 268) 'minus_...y ^= i': () +[267; 268) 'i': isize +[278; 281) 'ten': usize +[291; 293) '10': usize +[303; 316) 'ten_is_eleven': bool +[319; 322) 'ten': usize +[319; 334) 'ten == some_num': bool +[326; 334) 'some_num': usize +[341; 344) 'ten': usize +[341; 348) 'ten < 3': bool +[347; 348) '3': usize diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index 8d6079c98..6e82f458f 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -1,4 +1,4 @@ -[11; 101) '{ ...lse; }': () +[11; 111) '{ ...rue; }': () [17; 21) '5i32': i32 [27; 34) '"hello"': &str [40; 48) 'b"bytes"': &[u8] @@ -7,3 +7,4 @@ [73; 77) '3.14': f64 [83; 87) '5000': i32 [93; 98) 'false': bool +[104; 108) 'true': bool diff --git a/crates/ra_hir/src/ty/tests/data/tuple.txt b/crates/ra_hir/src/ty/tests/data/tuple.txt index 96169180d..a95d3c286 100644 --- a/crates/ra_hir/src/ty/tests/data/tuple.txt +++ b/crates/ra_hir/src/ty/tests/data/tuple.txt @@ -1,6 +1,6 @@ [9; 10) 'x': &str [18; 19) 'y': isize -[28; 214) '{ ...d"); }': () +[28; 170) '{ ...d"); }': () [38; 39) 'a': (u32, &str) [55; 63) '(1, "a")': (u32, &str) [56; 57) '1': u32 @@ -17,11 +17,11 @@ [117; 123) '(c, x)': ((isize, &str), &str) [118; 119) 'c': (isize, &str) [121; 122) 'x': &str -[177; 178) 'e': ([unknown], [unknown]) -[181; 189) '(1, "e")': ([unknown], [unknown]) -[182; 183) '1': [unknown] -[185; 188) '"e"': [unknown] -[199; 200) 'f': (([unknown], [unknown]), [unknown]) -[203; 211) '(e, "d")': (([unknown], [unknown]), [unknown]) -[204; 205) 'e': ([unknown], [unknown]) -[207; 210) '"d"': [unknown] +[133; 134) 'e': (i32, &str) +[137; 145) '(1, "e")': (i32, &str) +[138; 139) '1': i32 +[141; 144) '"e"': &str +[155; 156) 'f': ((i32, &str), &str) +[159; 167) '(e, "d")': ((i32, &str), &str) +[160; 161) 'e': (i32, &str) +[163; 166) '"d"': &str diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 8bf439b60..211ba31e5 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -609,6 +609,52 @@ impl SelfParam { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum LiteralFlavor { + String, + ByteString, + Char, + Byte, + IntNumber { suffix: Option }, + FloatNumber { suffix: Option }, + Bool, +} + +impl LiteralExpr { + pub fn flavor(&self) -> LiteralFlavor { + let syntax = self.syntax(); + match syntax.kind() { + INT_NUMBER => { + let allowed_suffix_list = [ + "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", + "u16", "u8", + ]; + let text = syntax.text().to_string(); + let suffix = allowed_suffix_list + .iter() + .find(|&s| text.ends_with(s)) + .map(|&suf| SmolStr::new(suf)); + LiteralFlavor::IntNumber { suffix: suffix } + } + FLOAT_NUMBER => { + let allowed_suffix_list = ["f64", "f32"]; + let text = syntax.text().to_string(); + let suffix = allowed_suffix_list + .iter() + .find(|&s| text.ends_with(s)) + .map(|&suf| SmolStr::new(suf)); + LiteralFlavor::FloatNumber { suffix: suffix } + } + STRING | RAW_STRING => LiteralFlavor::String, + TRUE_KW | FALSE_KW => LiteralFlavor::Bool, + BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString, + CHAR => LiteralFlavor::Char, + BYTE => LiteralFlavor::Byte, + _ => unreachable!(), + } + } +} + #[test] fn test_doc_comment_of_items() { let file = SourceFile::parse( diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 442659aee..cad845ec0 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -664,7 +664,7 @@ pub enum ExprKind<'a> { PrefixExpr(&'a PrefixExpr), RangeExpr(&'a RangeExpr), BinExpr(&'a BinExpr), - LiteralExpr(&'a LiteralExpr), + Literal(&'a Literal), } impl AstNode for Expr { @@ -696,7 +696,7 @@ impl AstNode for Expr { | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR - | LITERAL_EXPR => Some(Expr::from_repr(syntax.into_repr())), + | LITERAL => Some(Expr::from_repr(syntax.into_repr())), _ => None, } } @@ -733,7 +733,7 @@ impl Expr { PREFIX_EXPR => ExprKind::PrefixExpr(PrefixExpr::cast(&self.syntax).unwrap()), RANGE_EXPR => ExprKind::RangeExpr(RangeExpr::cast(&self.syntax).unwrap()), BIN_EXPR => ExprKind::BinExpr(BinExpr::cast(&self.syntax).unwrap()), - LITERAL_EXPR => ExprKind::LiteralExpr(LiteralExpr::cast(&self.syntax).unwrap()), + LITERAL => ExprKind::Literal(Literal::cast(&self.syntax).unwrap()), _ => unreachable!(), } } @@ -793,6 +793,31 @@ impl AstNode for ExternCrateItem { impl ExternCrateItem {} +// FalseKw +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct FalseKw { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for FalseKw { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for FalseKw { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for FalseKw {} +impl FalseKw {} + // FieldExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -867,7 +892,7 @@ impl AstNode for FloatNumber { } } fn syntax(&self) -> &SyntaxNode { &self.syntax } - fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } } @@ -1173,7 +1198,7 @@ impl AstNode for IntNumber { } } fn syntax(&self) -> &SyntaxNode { &self.syntax } - fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } } @@ -1365,25 +1390,10 @@ unsafe impl TransparentNewType for Literal { type Repr = rowan::SyntaxNode; } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LiteralKind<'a> { - String(&'a String), - ByteString(&'a ByteString), - Char(&'a Char), - Byte(&'a Byte), - IntNumber(&'a IntNumber), - FloatNumber(&'a FloatNumber), -} - impl AstNode for Literal { fn cast(syntax: &SyntaxNode) -> Option<&Self> { match syntax.kind() { - | STRING - | BYTE_STRING - | CHAR - | BYTE - | INT_NUMBER - | FLOAT_NUMBER => Some(Literal::from_repr(syntax.into_repr())), + LITERAL => Some(Literal::from_repr(syntax.into_repr())), _ => None, } } @@ -1391,22 +1401,13 @@ impl AstNode for Literal { fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } } + impl Literal { - pub fn kind(&self) -> LiteralKind { - match self.syntax.kind() { - STRING => LiteralKind::String(String::cast(&self.syntax).unwrap()), - BYTE_STRING => LiteralKind::ByteString(ByteString::cast(&self.syntax).unwrap()), - CHAR => LiteralKind::Char(Char::cast(&self.syntax).unwrap()), - BYTE => LiteralKind::Byte(Byte::cast(&self.syntax).unwrap()), - INT_NUMBER => LiteralKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), - FLOAT_NUMBER => LiteralKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), - _ => unreachable!(), - } + pub fn literal_expr(&self) -> Option<&LiteralExpr> { + super::child_opt(self) } } -impl Literal {} - // LiteralExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1417,24 +1418,54 @@ unsafe impl TransparentNewType for LiteralExpr { type Repr = rowan::SyntaxNode; } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LiteralExprKind<'a> { + String(&'a String), + ByteString(&'a ByteString), + Char(&'a Char), + Byte(&'a Byte), + IntNumber(&'a IntNumber), + FloatNumber(&'a FloatNumber), + TrueKw(&'a TrueKw), + FalseKw(&'a FalseKw), +} + impl AstNode for LiteralExpr { fn cast(syntax: &SyntaxNode) -> Option<&Self> { match syntax.kind() { - LITERAL_EXPR => Some(LiteralExpr::from_repr(syntax.into_repr())), + | STRING + | BYTE_STRING + | CHAR + | BYTE + | INT_NUMBER + | FLOAT_NUMBER + | TRUE_KW + | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())), _ => None, } } fn syntax(&self) -> &SyntaxNode { &self.syntax } - fn to_owned(&self) -> TreePtr { TreePtr::cast(self.syntax.to_owned()) } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } } - impl LiteralExpr { - pub fn literal(&self) -> Option<&Literal> { - super::child_opt(self) + pub fn kind(&self) -> LiteralExprKind { + match self.syntax.kind() { + STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()), + BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()), + CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()), + BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()), + INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), + FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), + TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()), + FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()), + _ => unreachable!(), + } } } +impl LiteralExpr {} + // LoopExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -3025,6 +3056,31 @@ impl ast::AttrsOwner for TraitDef {} impl ast::DocCommentsOwner for TraitDef {} impl TraitDef {} +// TrueKw +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct TrueKw { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for TrueKw { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for TrueKw { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for TrueKw {} +impl TrueKw {} + // TryExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 49b297696..34d2a27d1 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -215,7 +215,6 @@ Grammar( "PATH", "PATH_SEGMENT", "LITERAL", - "LITERAL_EXPR", "ALIAS", "VISIBILITY", "WHERE_CLAUSE", @@ -434,7 +433,9 @@ Grammar( "Byte": ( traits: ["AstToken"] ), "ByteString": ( traits: ["AstToken"] ), "Char": ( traits: ["AstToken"] ), - "Literal": ( + "TrueKw": ( traits: ["AstToken"] ), + "FalseKw": ( traits: ["AstToken"] ), + "LiteralExpr": ( enum: [ "String", "ByteString", @@ -442,9 +443,11 @@ Grammar( "Byte", "IntNumber", "FloatNumber", + "TrueKw", + "FalseKw", ] ), - "LiteralExpr": (options: ["Literal"]), + "Literal": (options: ["LiteralExpr"]), "Expr": ( enum: [ @@ -474,7 +477,7 @@ Grammar( "PrefixExpr", "RangeExpr", "BinExpr", - "LiteralExpr", + "Literal", ], ), diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 6181df9d7..bc311cbbc 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -59,7 +59,7 @@ impl SourceFile { assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); TreeArc::cast(root) } - + pub fn parse(text: &str) -> TreeArc { let tokens = tokenize(&text); let (green, errors) = diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs index 46795d6e9..830fac9f4 100644 --- a/crates/ra_syntax/src/syntax_kinds/generated.rs +++ b/crates/ra_syntax/src/syntax_kinds/generated.rs @@ -205,7 +205,6 @@ pub enum SyntaxKind { PATH, PATH_SEGMENT, LITERAL, - LITERAL_EXPR, ALIAS, VISIBILITY, WHERE_CLAUSE, @@ -468,7 +467,6 @@ impl SyntaxKind { PATH => &SyntaxInfo { name: "PATH" }, PATH_SEGMENT => &SyntaxInfo { name: "PATH_SEGMENT" }, LITERAL => &SyntaxInfo { name: "LITERAL" }, - LITERAL_EXPR => &SyntaxInfo { name: "LITERAL_EXPR" }, ALIAS => &SyntaxInfo { name: "ALIAS" }, VISIBILITY => &SyntaxInfo { name: "VISIBILITY" }, WHERE_CLAUSE => &SyntaxInfo { name: "WHERE_CLAUSE" }, -- cgit v1.2.3 From 26893487722d07b3f31a6addfc88e6948620989c Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 14 Jan 2019 19:46:10 +0100 Subject: Give literal expression default values for now --- crates/ra_hir/src/expr.rs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 2f3432870..2696592a4 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -654,7 +654,6 @@ impl ExprCollector { } else { return self.alloc_expr(Expr::Missing, syntax_ptr); }; - let c = child.syntax(); let lit = match child.flavor() { LiteralFlavor::IntNumber { suffix } => { @@ -663,9 +662,9 @@ impl ExprCollector { .and_then(|name| UncertainIntTy::from_name(&name)); if let Some(kn) = known_name { - Literal::Int(0u64, kn) + Literal::Int(Default::default(), kn) } else { - Literal::Int(0u64, UncertainIntTy::Unknown) + Literal::Int(Default::default(), UncertainIntTy::Unknown) } } LiteralFlavor::FloatNumber { suffix } => { @@ -674,31 +673,18 @@ impl ExprCollector { .and_then(|name| UncertainFloatTy::from_name(&name)); if let Some(kn) = known_name { - Literal::Float(0u64, kn) + Literal::Float(Default::default(), kn) } else { - Literal::Float(0u64, UncertainFloatTy::Unknown) + Literal::Float(Default::default(), UncertainFloatTy::Unknown) } } - LiteralFlavor::ByteString => { - // FIXME: this is completely incorrect for a variety - // of reasons, but at least it gives the right type - let bytes = c.text().to_string().into_bytes(); - Literal::ByteString(bytes) - } - LiteralFlavor::String => { - // FIXME: this likely includes the " characters - let text = c.text().to_string(); - Literal::String(text) - } + LiteralFlavor::ByteString => Literal::ByteString(Default::default()), + LiteralFlavor::String => Literal::String(Default::default()), LiteralFlavor::Byte => { - let character = c.text().char_at(1).unwrap_or('X'); - Literal::Int(character as u8 as u64, UncertainIntTy::Unsigned(UintTy::U8)) - } - LiteralFlavor::Bool => Literal::Bool(true), - LiteralFlavor::Char => { - let character = c.text().char_at(1).unwrap_or('X'); - Literal::Char(character) + Literal::Int(Default::default(), UncertainIntTy::Unsigned(UintTy::U8)) } + LiteralFlavor::Bool => Literal::Bool(Default::default()), + LiteralFlavor::Char => Literal::Char(Default::default()), }; self.alloc_expr(Expr::Literal(lit), syntax_ptr) } -- cgit v1.2.3 From d67eabb512a08a451a649c7f20e4e9ae1860a8a0 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 14 Jan 2019 20:56:14 +0100 Subject: Fix type inference for raw (byte) strings --- crates/ra_hir/src/ty/tests.rs | 12 ++++-- crates/ra_hir/src/ty/tests/data/literals.txt | 4 +- crates/ra_ide_api/src/hover.rs | 5 +-- crates/ra_syntax/src/ast/generated.rs | 56 ++++++++++++++++++++++++++++ crates/ra_syntax/src/grammar.ron | 4 ++ crates/ra_syntax/src/lexer/strings.rs | 15 +------- 6 files changed, 75 insertions(+), 21 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index cbdb2a4b7..8aacb1a7f 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -135,7 +135,7 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { #[test] fn infer_literals() { check_inference( - r#" + r##" fn test() { 5i32; "hello"; @@ -146,8 +146,14 @@ fn test() { 5000; false; true; -} -"#, + r#" + //! doc + // non-doc + mod foo {} + "#; + br#"yolo"#; +} +"##, "literals.txt", ); } diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index 6e82f458f..84ee2c11b 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -1,4 +1,4 @@ -[11; 111) '{ ...rue; }': () +[11; 201) '{ ...o"#; }': () [17; 21) '5i32': i32 [27; 34) '"hello"': &str [40; 48) 'b"bytes"': &[u8] @@ -8,3 +8,5 @@ [83; 87) '5000': i32 [93; 98) 'false': bool [104; 108) 'true': bool +[114; 182) 'r#" ... "#': &str +[188; 198) 'br#"yolo"#': &[u8] diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index d73c5bc31..107b23833 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -230,20 +230,19 @@ mod tests { assert_eq!("[unknown]", &type_name); } - // FIXME: improve type_of to make this work #[test] fn test_type_of_for_expr_2() { let (analysis, range) = single_file_with_range( " fn main() { let foo: usize = 1; - let bar = <|>1 + foo_test<|>; + let bar = <|>1 + foo<|>; } ", ); let type_name = analysis.type_of(range).unwrap().unwrap(); - assert_eq!("[unknown]", &type_name); + assert_eq!("usize", &type_name); } } diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index cad845ec0..3471d5226 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -1422,6 +1422,8 @@ unsafe impl TransparentNewType for LiteralExpr { pub enum LiteralExprKind<'a> { String(&'a String), ByteString(&'a ByteString), + RawString(&'a RawString), + RawByteString(&'a RawByteString), Char(&'a Char), Byte(&'a Byte), IntNumber(&'a IntNumber), @@ -1435,6 +1437,8 @@ impl AstNode for LiteralExpr { match syntax.kind() { | STRING | BYTE_STRING + | RAW_STRING + | RAW_BYTE_STRING | CHAR | BYTE | INT_NUMBER @@ -1453,6 +1457,8 @@ impl LiteralExpr { match self.syntax.kind() { STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()), BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()), + RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()), + RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()), CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()), BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()), INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), @@ -2543,6 +2549,56 @@ impl AstNode for RangePat { impl RangePat {} +// RawByteString +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct RawByteString { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for RawByteString { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for RawByteString { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for RawByteString {} +impl RawByteString {} + +// RawString +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct RawString { + pub(crate) syntax: SyntaxNode, +} +unsafe impl TransparentNewType for RawString { + type Repr = rowan::SyntaxNode; +} + +impl AstNode for RawString { + fn cast(syntax: &SyntaxNode) -> Option<&Self> { + match syntax.kind() { + RAW_STRING => Some(RawString::from_repr(syntax.into_repr())), + _ => None, + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } + fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } +} + + +impl ast::AstToken for RawString {} +impl RawString {} + // RefExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 34d2a27d1..bd8c5b411 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -430,7 +430,9 @@ Grammar( "IntNumber": ( traits: ["AstToken"] ), "FloatNumber": ( traits: ["AstToken"] ), "String": ( traits: ["AstToken"] ), + "RawString": ( traits: ["AstToken"] ), "Byte": ( traits: ["AstToken"] ), + "RawByteString": ( traits: ["AstToken"] ), "ByteString": ( traits: ["AstToken"] ), "Char": ( traits: ["AstToken"] ), "TrueKw": ( traits: ["AstToken"] ), @@ -439,6 +441,8 @@ Grammar( enum: [ "String", "ByteString", + "RawString", + "RawByteString", "Char", "Byte", "IntNumber", diff --git a/crates/ra_syntax/src/lexer/strings.rs b/crates/ra_syntax/src/lexer/strings.rs index 5090feae6..0865b7f3b 100644 --- a/crates/ra_syntax/src/lexer/strings.rs +++ b/crates/ra_syntax/src/lexer/strings.rs @@ -49,7 +49,7 @@ pub(crate) fn scan_byte_char_or_string(ptr: &mut Ptr) -> SyntaxKind { BYTE_STRING } 'r' => { - scan_raw_byte_string(ptr); + scan_raw_string(ptr); RAW_BYTE_STRING } _ => unreachable!(), @@ -108,16 +108,3 @@ fn scan_byte(ptr: &mut Ptr) { fn scan_byte_string(ptr: &mut Ptr) { scan_string(ptr) } - -fn scan_raw_byte_string(ptr: &mut Ptr) { - if !ptr.at('"') { - return; - } - ptr.bump(); - - while let Some(c) = ptr.bump() { - if c == '"' { - return; - } - } -} -- cgit v1.2.3 From 37ba237e6686d94783d1f025d23823ad7c0cb0c8 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 14 Jan 2019 21:52:08 +0100 Subject: Address issues found in review --- crates/ra_hir/src/expr.rs | 18 ++++++++---------- crates/ra_hir/src/ty.rs | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 2696592a4..5081466a2 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -661,22 +661,20 @@ impl ExprCollector { .map(|s| Name::new(s)) .and_then(|name| UncertainIntTy::from_name(&name)); - if let Some(kn) = known_name { - Literal::Int(Default::default(), kn) - } else { - Literal::Int(Default::default(), UncertainIntTy::Unknown) - } + Literal::Int( + Default::default(), + known_name.unwrap_or(UncertainIntTy::Unknown), + ) } LiteralFlavor::FloatNumber { suffix } => { let known_name = suffix .map(|s| Name::new(s)) .and_then(|name| UncertainFloatTy::from_name(&name)); - if let Some(kn) = known_name { - Literal::Float(Default::default(), kn) - } else { - Literal::Float(Default::default(), UncertainFloatTy::Unknown) - } + Literal::Float( + Default::default(), + known_name.unwrap_or(UncertainFloatTy::Unknown), + ) } LiteralFlavor::ByteString => Literal::ByteString(Default::default()), LiteralFlavor::String => Literal::String(Default::default()), diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index b6577ee5e..5579db8fb 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -107,7 +107,7 @@ impl UnifyValue for TypeVarValue { } } -/// The kinds of placeholders we need during type inference. There's seperate +/// The kinds of placeholders we need during type inference. There's separate /// values for general types, and for integer and float variables. The latter /// two are used for inference of literal values (e.g. `100` could be one of /// several integer types). -- cgit v1.2.3