From d09e5a3d9e57c631860ef195fad29f002569ae4d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 12 Nov 2019 15:09:25 +0300 Subject: Move definition of exprs to hir_def --- crates/ra_hir/src/expr.rs | 408 +-------------------------------- crates/ra_hir/src/expr/lower.rs | 82 ++----- crates/ra_hir/src/ty/infer/expr.rs | 4 +- crates/ra_hir/src/ty/lower.rs | 38 ++- crates/ra_hir/src/ty/primitive.rs | 26 --- crates/ra_hir_def/src/body.rs | 2 + crates/ra_hir_def/src/body/lower.rs | 49 ++++ crates/ra_hir_def/src/builtin_type.rs | 86 +++++-- crates/ra_hir_def/src/expr.rs | 419 ++++++++++++++++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 2 + 10 files changed, 598 insertions(+), 518 deletions(-) create mode 100644 crates/ra_hir_def/src/body.rs create mode 100644 crates/ra_hir_def/src/body/lower.rs create mode 100644 crates/ra_hir_def/src/expr.rs diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 53da7f0bf..dd2bae9b4 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -6,29 +6,18 @@ pub(crate) mod validation; use std::{ops::Index, sync::Arc}; -use hir_def::{ - path::GenericArgs, - type_ref::{Mutability, TypeRef}, -}; -use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; +use ra_arena::{map::ArenaMap, Arena}; use ra_syntax::{ast, AstPtr}; use rustc_hash::FxHashMap; -use crate::{ - db::HirDatabase, - ty::primitive::{UncertainFloatTy, UncertainIntTy}, - DefWithBody, Either, HasSource, Name, Path, Resolver, Source, -}; +use crate::{db::HirDatabase, DefWithBody, Either, HasSource, Resolver, Source}; pub use self::scope::ExprScopes; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ExprId(RawId); -impl_arena_id!(ExprId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct PatId(RawId); -impl_arena_id!(PatId); +pub use hir_def::expr::{ + ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, MatchArm, + Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, +}; /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] @@ -187,388 +176,3 @@ impl BodySourceMap { self.field_map[&(expr, field)] } } - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Literal { - String(String), - ByteString(Vec), - Char(char), - Bool(bool), - Int(u64, UncertainIntTy), - Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Expr { - /// This is produced if syntax tree does not have a required expression piece. - Missing, - Path(Path), - If { - condition: ExprId, - then_branch: ExprId, - else_branch: Option, - }, - Block { - statements: Vec, - tail: Option, - }, - Loop { - body: ExprId, - }, - While { - condition: ExprId, - body: ExprId, - }, - For { - iterable: ExprId, - pat: PatId, - body: ExprId, - }, - Call { - callee: ExprId, - args: Vec, - }, - MethodCall { - receiver: ExprId, - method_name: Name, - args: Vec, - generic_args: Option, - }, - Match { - expr: ExprId, - arms: Vec, - }, - Continue, - Break { - expr: Option, - }, - Return { - expr: Option, - }, - RecordLit { - path: Option, - fields: Vec, - spread: Option, - }, - Field { - expr: ExprId, - name: Name, - }, - Await { - expr: ExprId, - }, - Try { - expr: ExprId, - }, - TryBlock { - body: ExprId, - }, - Cast { - expr: ExprId, - type_ref: TypeRef, - }, - Ref { - expr: ExprId, - mutability: Mutability, - }, - Box { - expr: ExprId, - }, - UnaryOp { - expr: ExprId, - op: UnaryOp, - }, - BinaryOp { - lhs: ExprId, - rhs: ExprId, - op: Option, - }, - Index { - base: ExprId, - index: ExprId, - }, - Lambda { - args: Vec, - arg_types: Vec>, - body: ExprId, - }, - Tuple { - exprs: Vec, - }, - Array(Array), - Literal(Literal), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum BinaryOp { - LogicOp(LogicOp), - ArithOp(ArithOp), - CmpOp(CmpOp), - Assignment { op: Option }, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum LogicOp { - And, - Or, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum CmpOp { - Eq { negated: bool }, - Ord { ordering: Ordering, strict: bool }, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Ordering { - Less, - Greater, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ArithOp { - Add, - Mul, - Sub, - Div, - Rem, - Shl, - Shr, - BitXor, - BitOr, - BitAnd, -} - -pub use ra_syntax::ast::PrefixOp as UnaryOp; -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Array { - ElementList(Vec), - Repeat { initializer: ExprId, repeat: ExprId }, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct MatchArm { - pub pats: Vec, - pub guard: Option, - pub expr: ExprId, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct RecordLitField { - pub name: Name, - pub expr: ExprId, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Statement { - Let { pat: PatId, type_ref: Option, initializer: Option }, - Expr(ExprId), -} - -impl Expr { - pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { - match self { - Expr::Missing => {} - Expr::Path(_) => {} - Expr::If { condition, then_branch, else_branch } => { - f(*condition); - f(*then_branch); - if let Some(else_branch) = else_branch { - f(*else_branch); - } - } - Expr::Block { statements, tail } => { - for stmt in statements { - match stmt { - Statement::Let { initializer, .. } => { - if let Some(expr) = initializer { - f(*expr); - } - } - Statement::Expr(e) => f(*e), - } - } - if let Some(expr) = tail { - f(*expr); - } - } - Expr::TryBlock { body } => f(*body), - Expr::Loop { body } => f(*body), - Expr::While { condition, body } => { - f(*condition); - f(*body); - } - Expr::For { iterable, body, .. } => { - f(*iterable); - f(*body); - } - Expr::Call { callee, args } => { - f(*callee); - for arg in args { - f(*arg); - } - } - Expr::MethodCall { receiver, args, .. } => { - f(*receiver); - for arg in args { - f(*arg); - } - } - Expr::Match { expr, arms } => { - f(*expr); - for arm in arms { - f(arm.expr); - } - } - Expr::Continue => {} - Expr::Break { expr } | Expr::Return { expr } => { - if let Some(expr) = expr { - f(*expr); - } - } - Expr::RecordLit { fields, spread, .. } => { - for field in fields { - f(field.expr); - } - if let Some(expr) = spread { - f(*expr); - } - } - Expr::Lambda { body, .. } => { - f(*body); - } - Expr::BinaryOp { lhs, rhs, .. } => { - f(*lhs); - f(*rhs); - } - Expr::Index { base, index } => { - f(*base); - f(*index); - } - Expr::Field { expr, .. } - | Expr::Await { expr } - | Expr::Try { expr } - | Expr::Cast { expr, .. } - | Expr::Ref { expr, .. } - | Expr::UnaryOp { expr, .. } - | Expr::Box { expr } => { - f(*expr); - } - Expr::Tuple { exprs } => { - for expr in exprs { - f(*expr); - } - } - Expr::Array(a) => match a { - Array::ElementList(exprs) => { - for expr in exprs { - f(*expr); - } - } - Array::Repeat { initializer, repeat } => { - f(*initializer); - f(*repeat) - } - }, - Expr::Literal(_) => {} - } - } -} - -/// Explicit binding annotations given in the HIR for a binding. Note -/// that this is not the final binding *mode* that we infer after type -/// inference. -#[derive(Clone, PartialEq, Eq, Debug, Copy)] -pub enum BindingAnnotation { - /// No binding annotation given: this means that the final binding mode - /// will depend on whether we have skipped through a `&` reference - /// when matching. For example, the `x` in `Some(x)` will have binding - /// mode `None`; if you do `let Some(x) = &Some(22)`, it will - /// ultimately be inferred to be by-reference. - Unannotated, - - /// Annotated with `mut x` -- could be either ref or not, similar to `None`. - Mutable, - - /// Annotated as `ref`, like `ref x` - Ref, - - /// Annotated as `ref mut x`. - RefMut, -} - -impl BindingAnnotation { - fn new(is_mutable: bool, is_ref: bool) -> Self { - match (is_mutable, is_ref) { - (true, true) => BindingAnnotation::RefMut, - (false, true) => BindingAnnotation::Ref, - (true, false) => BindingAnnotation::Mutable, - (false, false) => BindingAnnotation::Unannotated, - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct RecordFieldPat { - pub(crate) name: Name, - pub(crate) pat: PatId, -} - -/// Close relative to rustc's hir::PatKind -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Pat { - Missing, - Wild, - Tuple(Vec), - Record { - path: Option, - args: Vec, - // FIXME: 'ellipsis' option - }, - Range { - start: ExprId, - end: ExprId, - }, - Slice { - prefix: Vec, - rest: Option, - suffix: Vec, - }, - Path(Path), - Lit(ExprId), - Bind { - mode: BindingAnnotation, - name: Name, - subpat: Option, - }, - TupleStruct { - path: Option, - args: Vec, - }, - Ref { - pat: PatId, - mutability: Mutability, - }, -} - -impl Pat { - pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { - match self { - Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} - Pat::Bind { subpat, .. } => { - subpat.iter().copied().for_each(f); - } - Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { - args.iter().copied().for_each(f); - } - Pat::Ref { pat, .. } => f(*pat), - Pat::Slice { prefix, rest, suffix } => { - let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); - total_iter.copied().for_each(f); - } - Pat::Record { args, .. } => { - args.iter().map(|f| f.pat).for_each(f); - } - } - } -} diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 6463dd65e..7b0bfd919 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,6 +1,10 @@ //! FIXME: write short doc here -use hir_def::{path::GenericArgs, type_ref::TypeRef}; +use hir_def::{ + builtin_type::{BuiltinFloat, BuiltinInt}, + path::GenericArgs, + type_ref::TypeRef, +}; use hir_expand::{ hygiene::Hygiene, name::{self, AsName, Name}, @@ -16,15 +20,13 @@ use ra_syntax::{ use test_utils::tested_by; use crate::{ - db::HirDatabase, - ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, - AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, - Source, + db::HirDatabase, AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, + Mutability, Path, Resolver, Source, }; use super::{ - ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal, - LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, + Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, Expr, ExprId, Literal, MatchArm, Pat, + PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, }; pub(super) fn lower( @@ -46,7 +48,7 @@ pub(super) fn lower( exprs: Arena::default(), pats: Arena::default(), params: Vec::new(), - body_expr: ExprId((!0).into()), + body_expr: ExprId::dummy(), }, } .collect(params, body) @@ -423,28 +425,18 @@ where ast::Expr::Literal(e) => { let lit = match e.kind() { LiteralKind::IntNumber { suffix } => { - let known_name = suffix - .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); + let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it)); - Literal::Int( - Default::default(), - known_name.unwrap_or(UncertainIntTy::Unknown), - ) + Literal::Int(Default::default(), known_name) } LiteralKind::FloatNumber { suffix } => { - let known_name = suffix - .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); + let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it)); - Literal::Float( - Default::default(), - known_name.unwrap_or(UncertainFloatTy::Unknown), - ) + Literal::Float(Default::default(), known_name) } LiteralKind::ByteString => Literal::ByteString(Default::default()), LiteralKind::String => Literal::String(Default::default()), - LiteralKind::Byte => { - Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) - } + LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)), LiteralKind::Bool => Literal::Bool(Default::default()), LiteralKind::Char => Literal::Char(Default::default()), }; @@ -601,47 +593,3 @@ where Path::from_src(path, &hygiene) } } - -impl From for BinaryOp { - fn from(ast_op: ast::BinOp) -> Self { - match ast_op { - ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or), - ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And), - ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), - ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), - ast::BinOp::LesserEqualTest => { - BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }) - } - ast::BinOp::GreaterEqualTest => { - BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }) - } - ast::BinOp::LesserTest => { - BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }) - } - ast::BinOp::GreaterTest => { - BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }) - } - ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add), - ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul), - ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub), - ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div), - ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem), - ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl), - ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr), - ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor), - ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr), - ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd), - ast::BinOp::Assignment => BinaryOp::Assignment { op: None }, - ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) }, - ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) }, - ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, - ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, - ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, - ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, - ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, - ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, - ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, - ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, - } - } -} diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 4af1d65ee..6d9792391 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -452,8 +452,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) } Literal::Char(..) => Ty::simple(TypeCtor::Char), - Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int(*ty)), - Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float(*ty)), + Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), + Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), }, }; // use a new type variable if we got Ty::Unknown here diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 52d24e24d..1832fcf50 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -25,7 +25,7 @@ use crate::{ generics::{GenericDef, WherePredicate}, resolve::{Resolver, TypeNs}, ty::{ - primitive::{FloatTy, IntTy}, + primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, Adt, }, util::make_mut_slice, @@ -657,13 +657,41 @@ fn type_for_builtin(def: BuiltinType) -> Ty { BuiltinType::Char => TypeCtor::Char, BuiltinType::Bool => TypeCtor::Bool, BuiltinType::Str => TypeCtor::Str, - BuiltinType::Int(BuiltinInt { signedness, bitness }) => { - TypeCtor::Int(IntTy { signedness, bitness }.into()) - } - BuiltinType::Float(BuiltinFloat { bitness }) => TypeCtor::Float(FloatTy { bitness }.into()), + BuiltinType::Int(t) => TypeCtor::Int(IntTy::from(t).into()), + BuiltinType::Float(t) => TypeCtor::Float(FloatTy::from(t).into()), }) } +impl From for IntTy { + fn from(t: BuiltinInt) -> Self { + IntTy { signedness: t.signedness, bitness: t.bitness } + } +} + +impl From for FloatTy { + fn from(t: BuiltinFloat) -> Self { + FloatTy { bitness: t.bitness } + } +} + +impl From> for UncertainIntTy { + fn from(t: Option) -> Self { + match t { + None => UncertainIntTy::Unknown, + Some(t) => UncertainIntTy::Known(t.into()), + } + } +} + +impl From> for UncertainFloatTy { + fn from(t: Option) -> Self { + match t { + None => UncertainFloatTy::Unknown, + Some(t) => UncertainFloatTy::Known(t.into()), + } + } +} + fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { let struct_data = db.struct_data(def.id.into()); let fields = match struct_data.variant_data.fields() { diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 1749752f1..7362de4c3 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs @@ -129,24 +129,6 @@ impl IntTy { (Signedness::Unsigned, IntBitness::X128) => "u128", } } - - pub(crate) fn from_suffix(suffix: &str) -> Option { - match suffix { - "isize" => Some(IntTy::isize()), - "i8" => Some(IntTy::i8()), - "i16" => Some(IntTy::i16()), - "i32" => Some(IntTy::i32()), - "i64" => Some(IntTy::i64()), - "i128" => Some(IntTy::i128()), - "usize" => Some(IntTy::usize()), - "u8" => Some(IntTy::u8()), - "u16" => Some(IntTy::u16()), - "u32" => Some(IntTy::u32()), - "u64" => Some(IntTy::u64()), - "u128" => Some(IntTy::u128()), - _ => None, - } - } } #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -181,12 +163,4 @@ impl FloatTy { FloatBitness::X64 => "f64", } } - - pub(crate) fn from_suffix(suffix: &str) -> Option { - match suffix { - "f32" => Some(FloatTy::f32()), - "f64" => Some(FloatTy::f64()), - _ => None, - } - } } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs new file mode 100644 index 000000000..7447904ea --- /dev/null +++ b/crates/ra_hir_def/src/body.rs @@ -0,0 +1,2 @@ +//! FIXME: write short doc here +mod lower; diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs new file mode 100644 index 000000000..1a144b1f9 --- /dev/null +++ b/crates/ra_hir_def/src/body/lower.rs @@ -0,0 +1,49 @@ +//! FIXME: write short doc here + +use ra_syntax::ast; + +use crate::expr::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering}; + +impl From for BinaryOp { + fn from(ast_op: ast::BinOp) -> Self { + match ast_op { + ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or), + ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And), + ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), + ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), + ast::BinOp::LesserEqualTest => { + BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }) + } + ast::BinOp::GreaterEqualTest => { + BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }) + } + ast::BinOp::LesserTest => { + BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }) + } + ast::BinOp::GreaterTest => { + BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }) + } + ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add), + ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul), + ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub), + ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div), + ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem), + ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl), + ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr), + ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor), + ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr), + ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd), + ast::BinOp::Assignment => BinaryOp::Assignment { op: None }, + ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) }, + ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) }, + ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, + ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, + ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, + ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, + ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, + ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, + ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, + ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, + } + } +} diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs index 996e86fd9..5e8157144 100644 --- a/crates/ra_hir_def/src/builtin_type.rs +++ b/crates/ra_hir_def/src/builtin_type.rs @@ -56,22 +56,22 @@ impl BuiltinType { (name::BOOL, BuiltinType::Bool), (name::STR, BuiltinType::Str ), - (name::ISIZE, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize })), - (name::I8, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 })), - (name::I16, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 })), - (name::I32, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 })), - (name::I64, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 })), - (name::I128, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 })), - - (name::USIZE, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize })), - (name::U8, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 })), - (name::U16, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 })), - (name::U32, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 })), - (name::U64, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 })), - (name::U128, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 })), - - (name::F32, BuiltinType::Float(BuiltinFloat { bitness: FloatBitness::X32 })), - (name::F64, BuiltinType::Float(BuiltinFloat { bitness: FloatBitness::X64 })), + (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), + (name::I8, BuiltinType::Int(BuiltinInt::I8)), + (name::I16, BuiltinType::Int(BuiltinInt::I16)), + (name::I32, BuiltinType::Int(BuiltinInt::I32)), + (name::I64, BuiltinType::Int(BuiltinInt::I64)), + (name::I128, BuiltinType::Int(BuiltinInt::I128)), + + (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), + (name::U8, BuiltinType::Int(BuiltinInt::U8)), + (name::U16, BuiltinType::Int(BuiltinInt::U16)), + (name::U32, BuiltinType::Int(BuiltinInt::U32)), + (name::U64, BuiltinType::Int(BuiltinInt::U64)), + (name::U128, BuiltinType::Int(BuiltinInt::U128)), + + (name::F32, BuiltinType::Float(BuiltinFloat::F32)), + (name::F64, BuiltinType::Float(BuiltinFloat::F64)), ]; } @@ -104,3 +104,57 @@ impl fmt::Display for BuiltinType { f.write_str(type_name) } } + +#[rustfmt::skip] +impl BuiltinInt { + pub const ISIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize }; + pub const I8 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 }; + pub const I16 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 }; + pub const I32 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 }; + pub const I64 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 }; + pub const I128 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 }; + + pub const USIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }; + pub const U8 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }; + pub const U16 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }; + pub const U32 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }; + pub const U64 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }; + pub const U128 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }; + + + pub fn from_suffix(suffix: &str) -> Option { + let res = match suffix { + "isize" => Self::ISIZE, + "i8" => Self::I8, + "i16" => Self::I16, + "i32" => Self::I32, + "i64" => Self::I64, + "i128" => Self::I128, + + "usize" => Self::USIZE, + "u8" => Self::U8, + "u16" => Self::U16, + "u32" => Self::U32, + "u64" => Self::U64, + "u128" => Self::U128, + + _ => return None, + }; + Some(res) + } +} + +#[rustfmt::skip] +impl BuiltinFloat { + pub const F32: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X32 }; + pub const F64: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X64 }; + + pub fn from_suffix(suffix: &str) -> Option { + let res = match suffix { + "f32" => BuiltinFloat::F32, + "f64" => BuiltinFloat::F64, + _ => return None, + }; + Some(res) + } +} diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs new file mode 100644 index 000000000..12eb0da68 --- /dev/null +++ b/crates/ra_hir_def/src/expr.rs @@ -0,0 +1,419 @@ +//! This module describes hir-level representation of expressions. +//! +//! This representaion is: +//! +//! 1. Identity-based. Each expression has an `id`, so we can distinguish +//! between different `1` in `1 + 1`. +//! 2. Independent of syntax. Though syntactic provenance information can be +//! attached separately via id-based side map. +//! 3. Unresolved. Paths are stored as sequences of names, and not as defs the +//! names refer to. +//! 4. Desugared. There's no `if let`. + +use hir_expand::name::Name; +use ra_arena::{impl_arena_id, RawId}; + +use crate::{ + builtin_type::{BuiltinFloat, BuiltinInt}, + path::{GenericArgs, Path}, + type_ref::{Mutability, TypeRef}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ExprId(RawId); +impl_arena_id!(ExprId); + +impl ExprId { + pub fn dummy() -> ExprId { + ExprId((!0).into()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct PatId(RawId); +impl_arena_id!(PatId); + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Literal { + String(String), + ByteString(Vec), + Char(char), + Bool(bool), + Int(u64, Option), + Float(u64, Option), // FIXME: f64 is not Eq +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Expr { + /// This is produced if syntax tree does not have a required expression piece. + Missing, + Path(Path), + If { + condition: ExprId, + then_branch: ExprId, + else_branch: Option, + }, + Block { + statements: Vec, + tail: Option, + }, + Loop { + body: ExprId, + }, + While { + condition: ExprId, + body: ExprId, + }, + For { + iterable: ExprId, + pat: PatId, + body: ExprId, + }, + Call { + callee: ExprId, + args: Vec, + }, + MethodCall { + receiver: ExprId, + method_name: Name, + args: Vec, + generic_args: Option, + }, + Match { + expr: ExprId, + arms: Vec, + }, + Continue, + Break { + expr: Option, + }, + Return { + expr: Option, + }, + RecordLit { + path: Option, + fields: Vec, + spread: Option, + }, + Field { + expr: ExprId, + name: Name, + }, + Await { + expr: ExprId, + }, + Try { + expr: ExprId, + }, + TryBlock { + body: ExprId, + }, + Cast { + expr: ExprId, + type_ref: TypeRef, + }, + Ref { + expr: ExprId, + mutability: Mutability, + }, + Box { + expr: ExprId, + }, + UnaryOp { + expr: ExprId, + op: UnaryOp, + }, + BinaryOp { + lhs: ExprId, + rhs: ExprId, + op: Option, + }, + Index { + base: ExprId, + index: ExprId, + }, + Lambda { + args: Vec, + arg_types: Vec>, + body: ExprId, + }, + Tuple { + exprs: Vec, + }, + Array(Array), + Literal(Literal), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum BinaryOp { + LogicOp(LogicOp), + ArithOp(ArithOp), + CmpOp(CmpOp), + Assignment { op: Option }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum LogicOp { + And, + Or, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CmpOp { + Eq { negated: bool }, + Ord { ordering: Ordering, strict: bool }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Ordering { + Less, + Greater, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ArithOp { + Add, + Mul, + Sub, + Div, + Rem, + Shl, + Shr, + BitXor, + BitOr, + BitAnd, +} + +pub use ra_syntax::ast::PrefixOp as UnaryOp; +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Array { + ElementList(Vec), + Repeat { initializer: ExprId, repeat: ExprId }, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MatchArm { + pub pats: Vec, + pub guard: Option, + pub expr: ExprId, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct RecordLitField { + pub name: Name, + pub expr: ExprId, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Statement { + Let { pat: PatId, type_ref: Option, initializer: Option }, + Expr(ExprId), +} + +impl Expr { + pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { + match self { + Expr::Missing => {} + Expr::Path(_) => {} + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let Some(else_branch) = else_branch { + f(*else_branch); + } + } + Expr::Block { statements, tail } => { + for stmt in statements { + match stmt { + Statement::Let { initializer, .. } => { + if let Some(expr) = initializer { + f(*expr); + } + } + Statement::Expr(e) => f(*e), + } + } + if let Some(expr) = tail { + f(*expr); + } + } + Expr::TryBlock { body } => f(*body), + Expr::Loop { body } => f(*body), + Expr::While { condition, body } => { + f(*condition); + f(*body); + } + Expr::For { iterable, body, .. } => { + f(*iterable); + f(*body); + } + Expr::Call { callee, args } => { + f(*callee); + for arg in args { + f(*arg); + } + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + for arg in args { + f(*arg); + } + } + Expr::Match { expr, arms } => { + f(*expr); + for arm in arms { + f(arm.expr); + } + } + Expr::Continue => {} + Expr::Break { expr } | Expr::Return { expr } => { + if let Some(expr) = expr { + f(*expr); + } + } + Expr::RecordLit { fields, spread, .. } => { + for field in fields { + f(field.expr); + } + if let Some(expr) = spread { + f(*expr); + } + } + Expr::Lambda { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Index { base, index } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Try { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs } => { + for expr in exprs { + f(*expr); + } + } + Expr::Array(a) => match a { + Array::ElementList(exprs) => { + for expr in exprs { + f(*expr); + } + } + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + Expr::Literal(_) => {} + } + } +} + +/// Explicit binding annotations given in the HIR for a binding. Note +/// that this is not the final binding *mode* that we infer after type +/// inference. +#[derive(Clone, PartialEq, Eq, Debug, Copy)] +pub enum BindingAnnotation { + /// No binding annotation given: this means that the final binding mode + /// will depend on whether we have skipped through a `&` reference + /// when matching. For example, the `x` in `Some(x)` will have binding + /// mode `None`; if you do `let Some(x) = &Some(22)`, it will + /// ultimately be inferred to be by-reference. + Unannotated, + + /// Annotated with `mut x` -- could be either ref or not, similar to `None`. + Mutable, + + /// Annotated as `ref`, like `ref x` + Ref, + + /// Annotated as `ref mut x`. + RefMut, +} + +impl BindingAnnotation { + pub fn new(is_mutable: bool, is_ref: bool) -> Self { + match (is_mutable, is_ref) { + (true, true) => BindingAnnotation::RefMut, + (false, true) => BindingAnnotation::Ref, + (true, false) => BindingAnnotation::Mutable, + (false, false) => BindingAnnotation::Unannotated, + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct RecordFieldPat { + pub name: Name, + pub pat: PatId, +} + +/// Close relative to rustc's hir::PatKind +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Pat { + Missing, + Wild, + Tuple(Vec), + Record { + path: Option, + args: Vec, + // FIXME: 'ellipsis' option + }, + Range { + start: ExprId, + end: ExprId, + }, + Slice { + prefix: Vec, + rest: Option, + suffix: Vec, + }, + Path(Path), + Lit(ExprId), + Bind { + mode: BindingAnnotation, + name: Name, + subpat: Option, + }, + TupleStruct { + path: Option, + args: Vec, + }, + Ref { + pat: PatId, + mutability: Mutability, + }, +} + +impl Pat { + pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { + match self { + Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} + Pat::Bind { subpat, .. } => { + subpat.iter().copied().for_each(f); + } + Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { + args.iter().copied().for_each(f); + } + Pat::Ref { pat, .. } => f(*pat), + Pat::Slice { prefix, rest, suffix } => { + let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); + total_iter.copied().for_each(f); + } + Pat::Record { args, .. } => { + args.iter().map(|f| f.pat).for_each(f); + } + } + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 239317efe..4a758bb83 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -14,6 +14,8 @@ pub mod type_ref; pub mod builtin_type; pub mod adt; pub mod diagnostics; +pub mod expr; +pub mod body; #[cfg(test)] mod test_db; -- cgit v1.2.3