mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-15 14:43:58 +00:00
Merge #1818
1818: Infer box expression r=matklad a=uHOOCCOOHu Infer `box e` to be `std::boxed::Box<T>` where `e: T` Co-authored-by: uHOOCCOOHu <hooccooh1896@gmail.com>
This commit is contained in:
commit
a1261631a8
7 changed files with 107 additions and 4 deletions
|
@ -237,6 +237,9 @@ pub enum Expr {
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
},
|
},
|
||||||
|
Box {
|
||||||
|
expr: ExprId,
|
||||||
|
},
|
||||||
UnaryOp {
|
UnaryOp {
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
op: UnaryOp,
|
op: UnaryOp,
|
||||||
|
@ -413,7 +416,8 @@ impl Expr {
|
||||||
| Expr::Try { expr }
|
| Expr::Try { expr }
|
||||||
| Expr::Cast { expr, .. }
|
| Expr::Cast { expr, .. }
|
||||||
| Expr::Ref { expr, .. }
|
| Expr::Ref { expr, .. }
|
||||||
| Expr::UnaryOp { expr, .. } => {
|
| Expr::UnaryOp { expr, .. }
|
||||||
|
| Expr::Box { expr } => {
|
||||||
f(*expr);
|
f(*expr);
|
||||||
}
|
}
|
||||||
Expr::Tuple { exprs } => {
|
Expr::Tuple { exprs } => {
|
||||||
|
|
|
@ -389,6 +389,10 @@ where
|
||||||
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::Expr::BoxExpr(e) => {
|
||||||
|
let expr = self.collect_expr_opt(e.expr());
|
||||||
|
self.alloc_expr(Expr::Box { expr }, syntax_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
ast::Expr::ArrayExpr(e) => {
|
ast::Expr::ArrayExpr(e) => {
|
||||||
let kind = e.kind();
|
let kind = e.kind();
|
||||||
|
|
|
@ -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 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 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 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 {
|
fn resolve_name(text: &SmolStr) -> SmolStr {
|
||||||
let raw_start = "r#";
|
let raw_start = "r#";
|
||||||
|
|
|
@ -1259,6 +1259,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let inner_ty = self.infer_expr(*expr, &expectation);
|
let inner_ty = self.infer_expr(*expr, &expectation);
|
||||||
Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
|
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 } => {
|
Expr::UnaryOp { expr, op } => {
|
||||||
let inner_ty = self.infer_expr(*expr, &Expectation::none());
|
let inner_ty = self.infer_expr(*expr, &Expectation::none());
|
||||||
match op {
|
match op {
|
||||||
|
@ -1499,6 +1507,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_boxed_box(&self) -> Option<AdtDef> {
|
||||||
|
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.
|
/// The ID of a type variable.
|
||||||
|
|
|
@ -55,6 +55,37 @@ mod future {
|
||||||
assert_eq!("u64", type_at_pos(&db, pos));
|
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<T: ?Sized> {
|
||||||
|
inner: *mut T,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
db.set_crate_graph_from_fixture(crate_graph! {
|
||||||
|
"main": ("/main.rs", ["std"]),
|
||||||
|
"std": ("/std.rs", []),
|
||||||
|
});
|
||||||
|
assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_try() {
|
fn infer_try() {
|
||||||
let (mut db, pos) = MockDatabase::with_position(
|
let (mut db, pos) = MockDatabase::with_position(
|
||||||
|
|
|
@ -307,6 +307,33 @@ impl BlockExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[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<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode {
|
||||||
|
&self.syntax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BoxExpr {
|
||||||
|
pub fn expr(&self) -> Option<Expr> {
|
||||||
|
AstChildren::new(&self.syntax).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct BoxPat {
|
pub struct BoxPat {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
|
@ -649,6 +676,7 @@ pub enum Expr {
|
||||||
BinExpr(BinExpr),
|
BinExpr(BinExpr),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
MacroCall(MacroCall),
|
MacroCall(MacroCall),
|
||||||
|
BoxExpr(BoxExpr),
|
||||||
}
|
}
|
||||||
impl From<TupleExpr> for Expr {
|
impl From<TupleExpr> for Expr {
|
||||||
fn from(node: TupleExpr) -> Expr {
|
fn from(node: TupleExpr) -> Expr {
|
||||||
|
@ -800,6 +828,11 @@ impl From<MacroCall> for Expr {
|
||||||
Expr::MacroCall(node)
|
Expr::MacroCall(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<BoxExpr> for Expr {
|
||||||
|
fn from(node: BoxExpr) -> Expr {
|
||||||
|
Expr::BoxExpr(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl AstNode for Expr {
|
impl AstNode for Expr {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -807,9 +840,8 @@ impl AstNode for Expr {
|
||||||
| LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL
|
| LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL
|
||||||
| BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR
|
| BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR
|
||||||
| METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_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 => {
|
| CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL
|
||||||
true
|
| BOX_EXPR => true,
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,6 +877,7 @@ impl AstNode for Expr {
|
||||||
BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
|
BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
|
||||||
LITERAL => Expr::Literal(Literal { syntax }),
|
LITERAL => Expr::Literal(Literal { syntax }),
|
||||||
MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
|
MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
|
||||||
|
BOX_EXPR => Expr::BoxExpr(BoxExpr { syntax }),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
@ -881,6 +914,7 @@ impl AstNode for Expr {
|
||||||
Expr::BinExpr(it) => &it.syntax,
|
Expr::BinExpr(it) => &it.syntax,
|
||||||
Expr::Literal(it) => &it.syntax,
|
Expr::Literal(it) => &it.syntax,
|
||||||
Expr::MacroCall(it) => &it.syntax,
|
Expr::MacroCall(it) => &it.syntax,
|
||||||
|
Expr::BoxExpr(it) => &it.syntax,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,6 +483,7 @@ Grammar(
|
||||||
"CastExpr": (options: ["Expr", "TypeRef"]),
|
"CastExpr": (options: ["Expr", "TypeRef"]),
|
||||||
"RefExpr": (options: ["Expr"]),
|
"RefExpr": (options: ["Expr"]),
|
||||||
"PrefixExpr": (options: ["Expr"]),
|
"PrefixExpr": (options: ["Expr"]),
|
||||||
|
"BoxExpr": (options: ["Expr"]),
|
||||||
"RangeExpr": (),
|
"RangeExpr": (),
|
||||||
"BinExpr": (),
|
"BinExpr": (),
|
||||||
|
|
||||||
|
@ -520,6 +521,7 @@ Grammar(
|
||||||
"BinExpr",
|
"BinExpr",
|
||||||
"Literal",
|
"Literal",
|
||||||
"MacroCall",
|
"MacroCall",
|
||||||
|
"BoxExpr",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue