mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 14:51:48 +00:00
Try implementing integer type inference (WIP)
This commit is contained in:
parent
a6146d35b1
commit
5f5dc20d85
8 changed files with 129 additions and 46 deletions
|
@ -11,6 +11,7 @@ use ra_syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ExprId(RawId);
|
pub struct ExprId(RawId);
|
||||||
|
@ -112,9 +113,8 @@ pub enum Literal {
|
||||||
ByteString(Vec<u8>),
|
ByteString(Vec<u8>),
|
||||||
Char(char),
|
Char(char),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Byte(u8),
|
Int(u64, UncertainIntTy),
|
||||||
Int, // this and float need additional information
|
Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq
|
||||||
Float,
|
|
||||||
Tuple { values: Vec<ExprId> },
|
Tuple { values: Vec<ExprId> },
|
||||||
Array { values: Vec<ExprId> },
|
Array { values: Vec<ExprId> },
|
||||||
}
|
}
|
||||||
|
@ -328,13 +328,7 @@ impl Expr {
|
||||||
f(val);
|
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 {
|
if let Some(c) = child {
|
||||||
let lit = match c.kind() {
|
let lit = match c.kind() {
|
||||||
SyntaxKind::INT_NUMBER => Literal::Int,
|
SyntaxKind::INT_NUMBER => {
|
||||||
SyntaxKind::FLOAT_NUMBER => Literal::Float,
|
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 => {
|
SyntaxKind::STRING => {
|
||||||
// FIXME: this likely includes the " characters
|
// FIXME: this likely includes the " characters
|
||||||
let text = c.text().to_string();
|
let text = c.text().to_string();
|
||||||
|
@ -698,7 +727,10 @@ impl ExprCollector {
|
||||||
}
|
}
|
||||||
SyntaxKind::BYTE => {
|
SyntaxKind::BYTE => {
|
||||||
let character = c.text().char_at(1).unwrap_or('X');
|
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),
|
_ => return self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
//! rustc.
|
//! rustc.
|
||||||
|
|
||||||
mod autoderef;
|
mod autoderef;
|
||||||
mod primitive;
|
pub(crate) mod primitive;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
pub(crate) mod method_resolution;
|
pub(crate) mod method_resolution;
|
||||||
|
@ -151,14 +151,13 @@ pub enum Ty {
|
||||||
/// (a non-surrogate code point). Written as `char`.
|
/// (a non-surrogate code point). Written as `char`.
|
||||||
Char,
|
Char,
|
||||||
|
|
||||||
/// A primitive signed integer type. For example, `i32`.
|
/// A primitive integer type. For example, `i32`.
|
||||||
Int(primitive::IntTy),
|
Int(primitive::UncertainIntTy),
|
||||||
|
|
||||||
/// A primitive unsigned integer type. For example, `u32`.
|
|
||||||
Uint(primitive::UintTy),
|
|
||||||
|
|
||||||
|
// /// A primitive unsigned integer type. For example, `u32`.
|
||||||
|
// Uint(primitive::UintTy),
|
||||||
/// A primitive floating-point type. For example, `f64`.
|
/// A primitive floating-point type. For example, `f64`.
|
||||||
Float(primitive::FloatTy),
|
Float(primitive::UncertainFloatTy),
|
||||||
|
|
||||||
/// Structures, enumerations and unions.
|
/// Structures, enumerations and unions.
|
||||||
Adt {
|
Adt {
|
||||||
|
@ -318,11 +317,9 @@ impl Ty {
|
||||||
return Ok(Ty::Char);
|
return Ok(Ty::Char);
|
||||||
} else if let Some(KnownName::Str) = name.as_known_name() {
|
} else if let Some(KnownName::Str) = name.as_known_name() {
|
||||||
return Ok(Ty::Str);
|
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));
|
return Ok(Ty::Int(int_ty));
|
||||||
} else if let Some(uint_ty) = primitive::UintTy::from_name(name) {
|
} else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) {
|
||||||
return Ok(Ty::Uint(uint_ty));
|
|
||||||
} else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
|
|
||||||
return Ok(Ty::Float(float_ty));
|
return Ok(Ty::Float(float_ty));
|
||||||
} else if name.as_known_name() == Some(KnownName::SelfType) {
|
} else if name.as_known_name() == Some(KnownName::SelfType) {
|
||||||
return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
|
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::Bool => write!(f, "bool"),
|
||||||
Ty::Char => write!(f, "char"),
|
Ty::Char => write!(f, "char"),
|
||||||
Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
|
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::Float(t) => write!(f, "{}", t.ty_to_string()),
|
||||||
Ty::Str => write!(f, "str"),
|
Ty::Str => write!(f, "str"),
|
||||||
Ty::Slice(t) => write!(f, "[{}]", t),
|
Ty::Slice(t) => write!(f, "[{}]", t),
|
||||||
|
@ -587,7 +583,7 @@ fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
|
||||||
| BinaryOp::BitwiseAnd
|
| BinaryOp::BitwiseAnd
|
||||||
| BinaryOp::BitwiseOr
|
| BinaryOp::BitwiseOr
|
||||||
| BinaryOp::BitwiseXor => match rhs_ty {
|
| BinaryOp::BitwiseXor => match rhs_ty {
|
||||||
Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => rhs_ty,
|
Ty::Int(..) | Ty::Float(..) => rhs_ty,
|
||||||
_ => Ty::Unknown,
|
_ => Ty::Unknown,
|
||||||
},
|
},
|
||||||
BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => 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 {
|
match op {
|
||||||
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool,
|
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool,
|
||||||
BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
|
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,
|
_ => Ty::Unknown,
|
||||||
},
|
},
|
||||||
BinaryOp::LesserEqualTest
|
BinaryOp::LesserEqualTest
|
||||||
|
@ -625,7 +621,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
|
||||||
| BinaryOp::BitwiseAnd
|
| BinaryOp::BitwiseAnd
|
||||||
| BinaryOp::BitwiseOr
|
| BinaryOp::BitwiseOr
|
||||||
| BinaryOp::BitwiseXor => match lhs_ty {
|
| BinaryOp::BitwiseXor => match lhs_ty {
|
||||||
Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => lhs_ty,
|
Ty::Int(..) | Ty::Float(..) => lhs_ty,
|
||||||
_ => Ty::Unknown,
|
_ => Ty::Unknown,
|
||||||
},
|
},
|
||||||
_ => Ty::Unknown,
|
_ => Ty::Unknown,
|
||||||
|
@ -695,13 +691,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
match (&*ty1, &*ty2) {
|
match (&*ty1, &*ty2) {
|
||||||
(Ty::Unknown, ..) => true,
|
(Ty::Unknown, ..) => true,
|
||||||
(.., Ty::Unknown) => true,
|
(.., Ty::Unknown) => true,
|
||||||
(Ty::Bool, _)
|
(Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) {
|
||||||
| (Ty::Str, _)
|
(primitive::UncertainIntTy::Unknown, _)
|
||||||
| (Ty::Never, _)
|
| (_, primitive::UncertainIntTy::Unknown) => true,
|
||||||
| (Ty::Char, _)
|
_ => t1 == t2,
|
||||||
| (Ty::Int(..), Ty::Int(..))
|
},
|
||||||
| (Ty::Uint(..), Ty::Uint(..))
|
(Ty::Float(t1), Ty::Float(t2)) => match (t1, t2) {
|
||||||
| (Ty::Float(..), Ty::Float(..)) => ty1 == ty2,
|
(primitive::UncertainFloatTy::Unknown, _)
|
||||||
|
| (_, primitive::UncertainFloatTy::Unknown) => true,
|
||||||
|
_ => t1 == t2,
|
||||||
|
},
|
||||||
|
(Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
|
||||||
(
|
(
|
||||||
Ty::Adt {
|
Ty::Adt {
|
||||||
def_id: def_id1, ..
|
def_id: def_id1, ..
|
||||||
|
@ -1071,11 +1071,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
Literal::Bool(..) => Ty::Bool,
|
Literal::Bool(..) => Ty::Bool,
|
||||||
Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
|
Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
|
||||||
Literal::ByteString(..) => {
|
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));
|
let slice_type = Arc::new(Ty::Slice(byte_type));
|
||||||
Ty::Ref(slice_type, Mutability::Shared)
|
Ty::Ref(slice_type, Mutability::Shared)
|
||||||
}
|
}
|
||||||
Literal::Byte(..) => Ty::Uint(primitive::UintTy::U8),
|
|
||||||
Literal::Char(..) => Ty::Char,
|
Literal::Char(..) => Ty::Char,
|
||||||
Literal::Tuple { values } => {
|
Literal::Tuple { values } => {
|
||||||
let mut inner_tys = Vec::new();
|
let mut inner_tys = Vec::new();
|
||||||
|
@ -1095,8 +1096,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
// available
|
// available
|
||||||
Ty::Slice(Arc::new(inner_ty))
|
Ty::Slice(Arc::new(inner_ty))
|
||||||
}
|
}
|
||||||
// TODO
|
Literal::Int(_v, ty) => Ty::Int(*ty),
|
||||||
Literal::Int | Literal::Float => Ty::Unknown,
|
Literal::Float(_v, ty) => Ty::Float(*ty),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// use a new type variable if we got Ty::Unknown here
|
// use a new type variable if we got Ty::Unknown here
|
||||||
|
|
|
@ -2,6 +2,56 @@ use std::fmt;
|
||||||
|
|
||||||
use crate::{Name, KnownName};
|
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<UncertainIntTy> {
|
||||||
|
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<UncertainFloatTy> {
|
||||||
|
if let Some(ty) = FloatTy::from_name(name) {
|
||||||
|
Some(UncertainFloatTy::Known(ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
||||||
pub enum IntTy {
|
pub enum IntTy {
|
||||||
Isize,
|
Isize,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
[55; 56) 'b': isize
|
[55; 56) 'b': isize
|
||||||
[62; 63) 'c': !
|
[62; 63) 'c': !
|
||||||
[69; 70) 'd': &str
|
[69; 70) 'd': &str
|
||||||
[76; 82) '1usize': [unknown]
|
[76; 82) '1usize': usize
|
||||||
[88; 94) '1isize': [unknown]
|
[88; 94) '1isize': isize
|
||||||
[100; 106) '"test"': &str
|
[100; 106) '"test"': &str
|
||||||
[112; 118) '1.0f32': [unknown]
|
[112; 118) '1.0f32': [unknown]
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
[112; 113) 'y': bool
|
[112; 113) 'y': bool
|
||||||
[123; 134) 'minus_forty': isize
|
[123; 134) 'minus_forty': isize
|
||||||
[144; 152) '-40isize': isize
|
[144; 152) '-40isize': isize
|
||||||
[145; 152) '40isize': [unknown]
|
[145; 152) '40isize': isize
|
||||||
[162; 163) 'h': bool
|
[162; 163) 'h': bool
|
||||||
[166; 177) 'minus_forty': isize
|
[166; 177) 'minus_forty': isize
|
||||||
[166; 188) 'minus_...ONST_2': bool
|
[166; 188) 'minus_...ONST_2': bool
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[11; 71) '{ ...= b; }': ()
|
[11; 71) '{ ...= b; }': ()
|
||||||
[21; 22) 'a': [unknown]
|
[21; 22) 'a': isize
|
||||||
[25; 31) '1isize': [unknown]
|
[25; 31) '1isize': isize
|
||||||
[41; 42) 'b': usize
|
[41; 42) 'b': usize
|
||||||
[52; 53) '1': usize
|
[52; 53) '1': usize
|
||||||
[63; 64) 'c': usize
|
[63; 64) 'c': usize
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[11; 135) '{ ...lse] }': ()
|
[11; 135) '{ ...lse] }': ()
|
||||||
[17; 21) '5i32': [unknown]
|
[17; 21) '5i32': i32
|
||||||
[27; 34) '"hello"': &str
|
[27; 34) '"hello"': &str
|
||||||
[40; 48) 'b"bytes"': &[u8]
|
[40; 48) 'b"bytes"': &[u8]
|
||||||
[54; 57) ''c'': char
|
[54; 57) ''c'': char
|
||||||
|
|
|
@ -128,7 +128,7 @@ impl SyntaxNode {
|
||||||
pub(crate) fn root_data(&self) -> &Vec<SyntaxError> {
|
pub(crate) fn root_data(&self) -> &Vec<SyntaxError> {
|
||||||
self.0.root_data()
|
self.0.root_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
|
pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
|
||||||
self.0.replace_self(replacement)
|
self.0.replace_self(replacement)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue