From 8c078a01641518a6b093922d4b1d27d1a98bad08 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Wed, 11 Sep 2019 23:53:41 +0800 Subject: [PATCH] Infer box expression --- crates/ra_hir/src/expr.rs | 6 +++- crates/ra_hir/src/expr/lower.rs | 4 +++ crates/ra_hir/src/name.rs | 2 ++ crates/ra_hir/src/ty/infer.rs | 26 +++++++++++++++++ crates/ra_hir/src/ty/tests.rs | 31 +++++++++++++++++++++ crates/ra_syntax/src/ast/generated.rs | 40 +++++++++++++++++++++++++-- crates/ra_syntax/src/grammar.ron | 2 ++ 7 files changed, 107 insertions(+), 4 deletions(-) diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 698fa671b5e..b1bec2a68d7 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -237,6 +237,9 @@ pub enum Expr { expr: ExprId, mutability: Mutability, }, + Box { + expr: ExprId, + }, UnaryOp { expr: ExprId, op: UnaryOp, @@ -413,7 +416,8 @@ impl Expr { | Expr::Try { expr } | Expr::Cast { expr, .. } | Expr::Ref { expr, .. } - | Expr::UnaryOp { expr, .. } => { + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { f(*expr); } Expr::Tuple { exprs } => { diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 8bd041ff088..2be6f5421b5 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -389,6 +389,10 @@ where let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) } + ast::Expr::BoxExpr(e) => { + let expr = self.collect_expr_opt(e.expr()); + self.alloc_expr(Expr::Box { expr }, syntax_ptr) + } ast::Expr::ArrayExpr(e) => { let kind = e.kind(); diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 13bc901bc9f..abdfec296f7 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -119,6 +119,8 @@ pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); +pub(crate) const BOXED_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); +pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box")); fn resolve_name(text: &SmolStr) -> SmolStr { let raw_start = "r#"; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 9244ff3cb9f..1057bbbec6b 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -1259,6 +1259,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let inner_ty = self.infer_expr(*expr, &expectation); Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) } + Expr::Box { expr } => { + let inner_ty = self.infer_expr(*expr, &Expectation::none()); + if let Some(box_) = self.resolve_boxed_box() { + Ty::apply_one(TypeCtor::Adt(box_), inner_ty) + } else { + Ty::Unknown + } + } Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); match op { @@ -1499,6 +1507,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => None, } } + + fn resolve_boxed_box(&self) -> Option { + let boxed_box_path = Path { + kind: PathKind::Abs, + segments: vec![ + PathSegment { name: name::STD, args_and_bindings: None }, + PathSegment { name: name::BOXED_MOD, args_and_bindings: None }, + PathSegment { name: name::BOX_TYPE, args_and_bindings: None }, + ], + }; + + match self.resolver.resolve_path_segments(self.db, &boxed_box_path).into_fully_resolved() { + PerNs { types: Some(Def(ModuleDef::Struct(struct_))), .. } => { + Some(AdtDef::Struct(struct_)) + } + _ => None, + } + } } /// The ID of a type variable. diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 869ae13f194..9a5f6949db1 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -55,6 +55,37 @@ mod future { assert_eq!("u64", type_at_pos(&db, pos)); } +#[test] +fn infer_box() { + let (mut db, pos) = MockDatabase::with_position( + r#" +//- /main.rs + +fn test() { + let x = box 1; + let t = (x, box x, box &1, box [1]); + t<|>; +} + +//- /std.rs +#[prelude_import] use prelude::*; +mod prelude {} + +mod boxed { + pub struct Box { + inner: *mut T, + } +} + +"#, + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["std"]), + "std": ("/std.rs", []), + }); + assert_eq!("(Box, Box>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); +} + #[test] fn infer_try() { let (mut db, pos) = MockDatabase::with_position( diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index d274b6fbc0f..a8a231ef325 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -307,6 +307,33 @@ impl BlockExpr { } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BoxExpr { + pub(crate) syntax: SyntaxNode, +} +impl AstNode for BoxExpr { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + BOX_EXPR => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl BoxExpr { + pub fn expr(&self) -> Option { + AstChildren::new(&self.syntax).next() + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BoxPat { pub(crate) syntax: SyntaxNode, } @@ -649,6 +676,7 @@ pub enum Expr { BinExpr(BinExpr), Literal(Literal), MacroCall(MacroCall), + BoxExpr(BoxExpr), } impl From for Expr { fn from(node: TupleExpr) -> Expr { @@ -800,6 +828,11 @@ impl From for Expr { Expr::MacroCall(node) } } +impl From for Expr { + fn from(node: BoxExpr) -> Expr { + Expr::BoxExpr(node) + } +} impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { match kind { @@ -807,9 +840,8 @@ impl AstNode for Expr { | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_EXPR - | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL => { - true - } + | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL + | BOX_EXPR => true, _ => false, } } @@ -845,6 +877,7 @@ impl AstNode for Expr { BIN_EXPR => Expr::BinExpr(BinExpr { syntax }), LITERAL => Expr::Literal(Literal { syntax }), MACRO_CALL => Expr::MacroCall(MacroCall { syntax }), + BOX_EXPR => Expr::BoxExpr(BoxExpr { syntax }), _ => return None, }; Some(res) @@ -881,6 +914,7 @@ impl AstNode for Expr { Expr::BinExpr(it) => &it.syntax, Expr::Literal(it) => &it.syntax, Expr::MacroCall(it) => &it.syntax, + Expr::BoxExpr(it) => &it.syntax, } } } diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 993e58e645a..8f064711def 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -483,6 +483,7 @@ Grammar( "CastExpr": (options: ["Expr", "TypeRef"]), "RefExpr": (options: ["Expr"]), "PrefixExpr": (options: ["Expr"]), + "BoxExpr": (options: ["Expr"]), "RangeExpr": (), "BinExpr": (), @@ -520,6 +521,7 @@ Grammar( "BinExpr", "Literal", "MacroCall", + "BoxExpr", ], ),