mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Merge #524
524: Implement array inference r=flodiebold a=h-michael related #394 Co-authored-by: Hirokazu Hata <h.hata.ai.t@gmail.com>
This commit is contained in:
commit
454cc31358
6 changed files with 115 additions and 9 deletions
|
@ -197,6 +197,9 @@ pub enum Expr {
|
||||||
Tuple {
|
Tuple {
|
||||||
exprs: Vec<ExprId>,
|
exprs: Vec<ExprId>,
|
||||||
},
|
},
|
||||||
|
Array {
|
||||||
|
exprs: Vec<ExprId>,
|
||||||
|
},
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +315,7 @@ impl Expr {
|
||||||
| Expr::UnaryOp { expr, .. } => {
|
| Expr::UnaryOp { expr, .. } => {
|
||||||
f(*expr);
|
f(*expr);
|
||||||
}
|
}
|
||||||
Expr::Tuple { exprs } => {
|
Expr::Tuple { exprs } | Expr::Array { exprs } => {
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
f(*expr);
|
f(*expr);
|
||||||
}
|
}
|
||||||
|
@ -649,6 +652,10 @@ impl ExprCollector {
|
||||||
let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
|
let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
|
||||||
self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
|
self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::ArrayExpr(e) => {
|
||||||
|
let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
|
||||||
|
self.alloc_expr(Expr::Array { exprs }, syntax_ptr)
|
||||||
|
}
|
||||||
ast::ExprKind::Literal(e) => {
|
ast::ExprKind::Literal(e) => {
|
||||||
let child = if let Some(child) = e.literal_expr() {
|
let child = if let Some(child) = e.literal_expr() {
|
||||||
child
|
child
|
||||||
|
@ -691,7 +698,6 @@ impl ExprCollector {
|
||||||
// TODO implement HIR for these:
|
// TODO implement HIR for these:
|
||||||
ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
ast::ExprKind::IndexExpr(_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::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,11 +181,12 @@ pub enum Ty {
|
||||||
/// The pointee of a string slice. Written as `str`.
|
/// The pointee of a string slice. Written as `str`.
|
||||||
Str,
|
Str,
|
||||||
|
|
||||||
// An array with the given length. Written as `[T; n]`.
|
|
||||||
// Array(Ty, ty::Const),
|
|
||||||
/// The pointee of an array slice. Written as `[T]`.
|
/// The pointee of an array slice. Written as `[T]`.
|
||||||
Slice(Arc<Ty>),
|
Slice(Arc<Ty>),
|
||||||
|
|
||||||
|
// An array with the given length. Written as `[T; n]`.
|
||||||
|
Array(Arc<Ty>),
|
||||||
|
|
||||||
/// A raw pointer. Written as `*mut T` or `*const T`
|
/// A raw pointer. Written as `*mut T` or `*const T`
|
||||||
RawPtr(Arc<Ty>, Mutability),
|
RawPtr(Arc<Ty>, Mutability),
|
||||||
|
|
||||||
|
@ -276,7 +277,10 @@ impl Ty {
|
||||||
let inner_ty = Ty::from_hir(db, module, impl_block, inner);
|
let inner_ty = Ty::from_hir(db, module, impl_block, inner);
|
||||||
Ty::RawPtr(Arc::new(inner_ty), *mutability)
|
Ty::RawPtr(Arc::new(inner_ty), *mutability)
|
||||||
}
|
}
|
||||||
TypeRef::Array(_inner) => Ty::Unknown, // TODO
|
TypeRef::Array(inner) => {
|
||||||
|
let inner_ty = Ty::from_hir(db, module, impl_block, inner);
|
||||||
|
Ty::Array(Arc::new(inner_ty))
|
||||||
|
}
|
||||||
TypeRef::Slice(inner) => {
|
TypeRef::Slice(inner) => {
|
||||||
let inner_ty = Ty::from_hir(db, module, impl_block, inner);
|
let inner_ty = Ty::from_hir(db, module, impl_block, inner);
|
||||||
Ty::Slice(Arc::new(inner_ty))
|
Ty::Slice(Arc::new(inner_ty))
|
||||||
|
@ -352,7 +356,7 @@ impl Ty {
|
||||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||||
f(self);
|
f(self);
|
||||||
match self {
|
match self {
|
||||||
Ty::Slice(t) => Arc::make_mut(t).walk_mut(f),
|
Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f),
|
||||||
Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
|
Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
|
||||||
Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f),
|
Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f),
|
||||||
Ty::Tuple(ts) => {
|
Ty::Tuple(ts) => {
|
||||||
|
@ -400,7 +404,7 @@ impl fmt::Display for Ty {
|
||||||
Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
|
Ty::Int(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) | Ty::Array(t) => write!(f, "[{}]", t),
|
||||||
Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t),
|
Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t),
|
||||||
Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t),
|
Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t),
|
||||||
Ty::Never => write!(f, "!"),
|
Ty::Never => write!(f, "!"),
|
||||||
|
@ -1102,6 +1106,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
Ty::Tuple(Arc::from(ty_vec))
|
Ty::Tuple(Arc::from(ty_vec))
|
||||||
}
|
}
|
||||||
|
Expr::Array { exprs } => {
|
||||||
|
let elem_ty = match &expected.ty {
|
||||||
|
Ty::Slice(inner) | Ty::Array(inner) => Ty::clone(&inner),
|
||||||
|
_ => self.new_type_var(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for expr in exprs.iter() {
|
||||||
|
self.infer_expr(*expr, &Expectation::has_type(elem_ty.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ty::Array(Arc::new(elem_ty))
|
||||||
|
}
|
||||||
Expr::Literal(lit) => match lit {
|
Expr::Literal(lit) => match lit {
|
||||||
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),
|
||||||
|
|
|
@ -334,6 +334,32 @@ fn test(x: &str, y: isize) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_array() {
|
||||||
|
check_inference(
|
||||||
|
r#"
|
||||||
|
fn test(x: &str, y: isize) {
|
||||||
|
let a = [x];
|
||||||
|
let b = [a, a];
|
||||||
|
let c = [b, b];
|
||||||
|
|
||||||
|
let d = [y, 1, 2, 3];
|
||||||
|
let d = [1, y, 2, 3];
|
||||||
|
let e = [y];
|
||||||
|
let f = [d, d];
|
||||||
|
let g = [e, e];
|
||||||
|
|
||||||
|
let h = [1, 2];
|
||||||
|
let i = ["a", "b"];
|
||||||
|
|
||||||
|
let b = [a, ["b"]];
|
||||||
|
let x: [u8; 0] = [];
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"array.txt",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn infer(content: &str) -> String {
|
fn infer(content: &str) -> String {
|
||||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||||
let source_file = db.source_file(file_id);
|
let source_file = db.source_file(file_id);
|
||||||
|
|
52
crates/ra_hir/src/ty/tests/data/array.txt
Normal file
52
crates/ra_hir/src/ty/tests/data/array.txt
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
[9; 10) 'x': &str
|
||||||
|
[18; 19) 'y': isize
|
||||||
|
[28; 293) '{ ... []; }': ()
|
||||||
|
[38; 39) 'a': [&str]
|
||||||
|
[42; 45) '[x]': [&str]
|
||||||
|
[43; 44) 'x': &str
|
||||||
|
[55; 56) 'b': [[&str]]
|
||||||
|
[59; 65) '[a, a]': [[&str]]
|
||||||
|
[60; 61) 'a': [&str]
|
||||||
|
[63; 64) 'a': [&str]
|
||||||
|
[75; 76) 'c': [[[&str]]]
|
||||||
|
[79; 85) '[b, b]': [[[&str]]]
|
||||||
|
[80; 81) 'b': [[&str]]
|
||||||
|
[83; 84) 'b': [[&str]]
|
||||||
|
[96; 97) 'd': [isize]
|
||||||
|
[100; 112) '[y, 1, 2, 3]': [isize]
|
||||||
|
[101; 102) 'y': isize
|
||||||
|
[104; 105) '1': isize
|
||||||
|
[107; 108) '2': isize
|
||||||
|
[110; 111) '3': isize
|
||||||
|
[122; 123) 'd': [isize]
|
||||||
|
[126; 138) '[1, y, 2, 3]': [isize]
|
||||||
|
[127; 128) '1': isize
|
||||||
|
[130; 131) 'y': isize
|
||||||
|
[133; 134) '2': isize
|
||||||
|
[136; 137) '3': isize
|
||||||
|
[148; 149) 'e': [isize]
|
||||||
|
[152; 155) '[y]': [isize]
|
||||||
|
[153; 154) 'y': isize
|
||||||
|
[165; 166) 'f': [[isize]]
|
||||||
|
[169; 175) '[d, d]': [[isize]]
|
||||||
|
[170; 171) 'd': [isize]
|
||||||
|
[173; 174) 'd': [isize]
|
||||||
|
[185; 186) 'g': [[isize]]
|
||||||
|
[189; 195) '[e, e]': [[isize]]
|
||||||
|
[190; 191) 'e': [isize]
|
||||||
|
[193; 194) 'e': [isize]
|
||||||
|
[206; 207) 'h': [i32]
|
||||||
|
[210; 216) '[1, 2]': [i32]
|
||||||
|
[211; 212) '1': i32
|
||||||
|
[214; 215) '2': i32
|
||||||
|
[226; 227) 'i': [&str]
|
||||||
|
[230; 240) '["a", "b"]': [&str]
|
||||||
|
[231; 234) '"a"': &str
|
||||||
|
[236; 239) '"b"': &str
|
||||||
|
[251; 252) 'b': [[&str]]
|
||||||
|
[255; 265) '[a, ["b"]]': [[&str]]
|
||||||
|
[256; 257) 'a': [&str]
|
||||||
|
[259; 264) '["b"]': [&str]
|
||||||
|
[260; 263) '"b"': &str
|
||||||
|
[275; 276) 'x': [u8]
|
||||||
|
[288; 290) '[]': [u8]
|
|
@ -67,7 +67,11 @@ impl AstNode for ArrayExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ArrayExpr {}
|
impl ArrayExpr {
|
||||||
|
pub fn exprs(&self) -> impl Iterator<Item = &Expr> {
|
||||||
|
super::children(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ArrayType
|
// ArrayType
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -360,7 +360,9 @@ Grammar(
|
||||||
"TupleExpr": (
|
"TupleExpr": (
|
||||||
collections: [["exprs", "Expr"]]
|
collections: [["exprs", "Expr"]]
|
||||||
),
|
),
|
||||||
"ArrayExpr": (),
|
"ArrayExpr": (
|
||||||
|
collections: [["exprs", "Expr"]]
|
||||||
|
),
|
||||||
"ParenExpr": (options: ["Expr"]),
|
"ParenExpr": (options: ["Expr"]),
|
||||||
"PathExpr": (options: ["Path"]),
|
"PathExpr": (options: ["Path"]),
|
||||||
"LambdaExpr": (
|
"LambdaExpr": (
|
||||||
|
|
Loading…
Reference in a new issue