From b28c54a2c239acd73f2eea80fda9ee3960d2c046 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 16:28:27 +0200 Subject: Rename ra_hir_def -> hir_def --- crates/hir_def/src/expr.rs | 420 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 crates/hir_def/src/expr.rs (limited to 'crates/hir_def/src/expr.rs') diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs new file mode 100644 index 000000000..c94b3a36f --- /dev/null +++ b/crates/hir_def/src/expr.rs @@ -0,0 +1,420 @@ +//! 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`. +//! +//! See also a neighboring `body` module. + +use arena::{Idx, RawId}; +use hir_expand::name::Name; +use syntax::ast::RangeOp; + +use crate::{ + builtin_type::{BuiltinFloat, BuiltinInt}, + path::{GenericArgs, Path}, + type_ref::{Mutability, Rawness, TypeRef}, +}; + +pub type ExprId = Idx; +pub(crate) fn dummy_expr_id() -> ExprId { + ExprId::from_raw(RawId::from(!0)) +} + +pub type PatId = Idx; + +#[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 the 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, + label: Option, + }, + Loop { + body: ExprId, + label: Option, + }, + While { + condition: ExprId, + body: ExprId, + label: Option, + }, + For { + iterable: ExprId, + pat: PatId, + body: ExprId, + label: Option, + }, + Call { + callee: ExprId, + args: Vec, + }, + MethodCall { + receiver: ExprId, + method_name: Name, + args: Vec, + generic_args: Option, + }, + Match { + expr: ExprId, + arms: Vec, + }, + Continue { + label: Option, + }, + Break { + expr: Option, + label: 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, + rawness: Rawness, + mutability: Mutability, + }, + Box { + expr: ExprId, + }, + UnaryOp { + expr: ExprId, + op: UnaryOp, + }, + BinaryOp { + lhs: ExprId, + rhs: ExprId, + op: Option, + }, + Range { + lhs: Option, + rhs: Option, + range_type: RangeOp, + }, + Index { + base: ExprId, + index: ExprId, + }, + Lambda { + args: Vec, + arg_types: Vec>, + ret_type: Option, + body: ExprId, + }, + Tuple { + exprs: Vec, + }, + Unsafe { + body: ExprId, + }, + 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 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 pat: PatId, + 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 } | Expr::Unsafe { 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::Range { lhs, rhs, .. } => { + if let Some(lhs) = rhs { + f(*lhs); + } + if let Some(rhs) = 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 { args: Vec, ellipsis: Option }, + Or(Vec), + Record { path: Option, args: Vec, ellipsis: bool }, + Range { start: ExprId, end: ExprId }, + Slice { prefix: Vec, slice: Option, suffix: Vec }, + Path(Path), + Lit(ExprId), + Bind { mode: BindingAnnotation, name: Name, subpat: Option }, + TupleStruct { path: Option, args: Vec, ellipsis: Option }, + 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::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { + args.iter().copied().for_each(f); + } + Pat::Ref { pat, .. } => f(*pat), + Pat::Slice { prefix, slice, suffix } => { + let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); + total_iter.copied().for_each(f); + } + Pat::Record { args, .. } => { + args.iter().map(|f| f.pat).for_each(f); + } + } + } +} -- cgit v1.2.3