diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 66333884475..6e98ebc6976 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -197,6 +197,9 @@ pub enum Expr { Tuple { exprs: Vec, }, + Array { + exprs: Vec, + }, Literal(Literal), } @@ -312,7 +315,7 @@ impl Expr { | Expr::UnaryOp { expr, .. } => { f(*expr); } - Expr::Tuple { exprs } => { + Expr::Tuple { exprs } | Expr::Array { exprs } => { for expr in exprs { f(*expr); } @@ -649,6 +652,10 @@ impl ExprCollector { let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); 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) => { let child = if let Some(child) = e.literal_expr() { child @@ -691,7 +698,6 @@ impl ExprCollector { // 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), } } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 85d4dc05ce8..c7c0636017f 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -181,11 +181,12 @@ pub enum Ty { /// The pointee of a string slice. Written as `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]`. Slice(Arc), + // An array with the given length. Written as `[T; n]`. + Array(Arc), + /// A raw pointer. Written as `*mut T` or `*const T` RawPtr(Arc, Mutability), @@ -276,7 +277,10 @@ impl Ty { let inner_ty = Ty::from_hir(db, module, impl_block, inner); 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) => { let inner_ty = Ty::from_hir(db, module, impl_block, inner); Ty::Slice(Arc::new(inner_ty)) @@ -352,7 +356,7 @@ impl Ty { fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { f(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::Ref(t, _) => Arc::make_mut(t).walk_mut(f), Ty::Tuple(ts) => { @@ -400,7 +404,7 @@ impl fmt::Display for Ty { Ty::Int(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), + Ty::Slice(t) | Ty::Array(t) => write!(f, "[{}]", 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::Never => write!(f, "!"), @@ -1102,6 +1106,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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 { Literal::Bool(..) => Ty::Bool, Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared), diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 5d7bc25cc4b..affd63a8506 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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 { let (db, _, file_id) = MockDatabase::with_single_file(content); let source_file = db.source_file(file_id); diff --git a/crates/ra_hir/src/ty/tests/data/array.txt b/crates/ra_hir/src/ty/tests/data/array.txt new file mode 100644 index 00000000000..acdf74ba49d --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/array.txt @@ -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] diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 3471d522646..2d9603d904d 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -67,7 +67,11 @@ impl AstNode for ArrayExpr { } -impl ArrayExpr {} +impl ArrayExpr { + pub fn exprs(&self) -> impl Iterator { + super::children(self) + } +} // ArrayType #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index bd8c5b41106..2aaad46b1b5 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -360,7 +360,9 @@ Grammar( "TupleExpr": ( collections: [["exprs", "Expr"]] ), - "ArrayExpr": (), + "ArrayExpr": ( + collections: [["exprs", "Expr"]] + ), "ParenExpr": (options: ["Expr"]), "PathExpr": (options: ["Path"]), "LambdaExpr": (