wrap rest of IR indexes
[bigint-presentation-code.git] / register_allocator / src / error.rs
index d50421372a92fef759828b47d58d405ac1875c29..30fe203462077fdbcfa3ec8ba112091f77895540 100644 (file)
 use crate::{
-    index::{BlockIdx, DisplayOptionIdx, InstIdx, SSAValIdx},
+    index::{BlockIdx, BlockParamIdx, DisplayOptionIdx, IndexTy, InstIdx, OperandIdx, SSAValIdx},
     loc::{BaseTy, Ty},
 };
+use std::fmt;
 use thiserror::Error;
 
+#[derive(Debug, Error)]
+#[error("SSA value index {idx} out of range")]
+pub struct SSAValIdxOutOfRange {
+    pub idx: SSAValIdx,
+}
+
+impl SSAValIdxOutOfRange {
+    pub fn with_inst_and_operand(
+        self,
+        inst: InstIdx,
+        operand: OperandIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        AlwaysNone,
+        OperandIdx,
+        AlwaysNone,
+        SSAValIdxOutOfRange,
+    > {
+        WithContext {
+            block: None,
+            inst,
+            succ: AlwaysNone,
+            operand,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_block_inst_and_operand(
+        self,
+        block: BlockIdx,
+        inst: InstIdx,
+        operand: OperandIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        AlwaysNone,
+        OperandIdx,
+        AlwaysNone,
+        SSAValIdxOutOfRange,
+    > {
+        WithContext {
+            block: Some(block),
+            inst,
+            succ: AlwaysNone,
+            operand,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_inst_succ_and_param(
+        self,
+        inst: InstIdx,
+        succ: BlockIdx,
+        param: BlockParamIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        BlockIdx,
+        AlwaysNone,
+        BlockParamIdx,
+        SSAValIdxOutOfRange,
+    > {
+        WithContext {
+            block: None,
+            inst,
+            succ,
+            operand: AlwaysNone,
+            param,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_block_inst_succ_and_param(
+        self,
+        block: BlockIdx,
+        inst: InstIdx,
+        succ: BlockIdx,
+        param: BlockParamIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        BlockIdx,
+        AlwaysNone,
+        BlockParamIdx,
+        SSAValIdxOutOfRange,
+    > {
+        WithContext {
+            block: Some(block),
+            inst,
+            succ,
+            operand: AlwaysNone,
+            param,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_block_and_param(
+        self,
+        block: BlockIdx,
+        param: BlockParamIdx,
+    ) -> WithContext<BlockIdx, AlwaysNone, AlwaysNone, AlwaysNone, BlockParamIdx, SSAValIdxOutOfRange>
+    {
+        WithContext {
+            block,
+            inst: AlwaysNone,
+            succ: AlwaysNone,
+            operand: AlwaysNone,
+            param,
+            out_of_range_error: self,
+        }
+    }
+}
+
+#[derive(Debug, Error)]
+#[error("instruction index {idx} out of range")]
+pub struct InstIdxOutOfRange {
+    pub idx: InstIdx,
+}
+
+impl InstIdxOutOfRange {
+    pub fn with_block(
+        self,
+        block: BlockIdx,
+    ) -> WithContext<BlockIdx, AlwaysNone, AlwaysNone, AlwaysNone, AlwaysNone, InstIdxOutOfRange>
+    {
+        WithContext {
+            block,
+            inst: AlwaysNone,
+            succ: AlwaysNone,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+}
+
+#[derive(Debug, Error)]
+#[error("block index {idx} out of range")]
+pub struct BlockIdxOutOfRange {
+    pub idx: BlockIdx,
+}
+
+#[derive(Debug, Error)]
+#[error("block parameter index {idx} is out of range")]
+pub struct BlockParamIdxOutOfRange {
+    pub idx: BlockParamIdx,
+}
+
+impl BlockParamIdxOutOfRange {
+    pub fn with_block(
+        self,
+        block: BlockIdx,
+    ) -> WithContext<
+        BlockIdx,
+        AlwaysNone,
+        AlwaysNone,
+        AlwaysNone,
+        AlwaysNone,
+        BlockParamIdxOutOfRange,
+    > {
+        WithContext {
+            block,
+            inst: AlwaysNone,
+            succ: AlwaysNone,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_block_inst_and_succ(
+        self,
+        block: BlockIdx,
+        inst: InstIdx,
+        succ: BlockIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        BlockIdx,
+        AlwaysNone,
+        AlwaysNone,
+        BlockParamIdxOutOfRange,
+    > {
+        WithContext {
+            block: Some(block),
+            inst,
+            succ,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_inst_and_succ(
+        self,
+        inst: InstIdx,
+        succ: BlockIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        BlockIdx,
+        AlwaysNone,
+        AlwaysNone,
+        BlockParamIdxOutOfRange,
+    > {
+        WithContext {
+            block: None,
+            inst,
+            succ,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+}
+
+#[derive(Debug, Error)]
+#[error("operand index {idx} is out of range")]
+pub struct OperandIdxOutOfRange {
+    pub idx: OperandIdx,
+}
+
+impl OperandIdxOutOfRange {
+    pub fn with_block_and_inst(
+        self,
+        block: BlockIdx,
+        inst: InstIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        AlwaysNone,
+        AlwaysNone,
+        AlwaysNone,
+        OperandIdxOutOfRange,
+    > {
+        WithContext {
+            block: Some(block),
+            inst,
+            succ: AlwaysNone,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+    pub fn with_inst(
+        self,
+        inst: InstIdx,
+    ) -> WithContext<
+        Option<BlockIdx>,
+        InstIdx,
+        AlwaysNone,
+        AlwaysNone,
+        AlwaysNone,
+        OperandIdxOutOfRange,
+    > {
+        WithContext {
+            block: None,
+            inst,
+            succ: AlwaysNone,
+            operand: AlwaysNone,
+            param: AlwaysNone,
+            out_of_range_error: self,
+        }
+    }
+}
+
+#[derive(Default, Clone, Copy, Debug)]
+pub struct AlwaysNone;
+
+pub trait ToContextValue<T: IndexTy>: fmt::Debug + Copy {
+    fn to_context_value(self) -> Option<T>;
+}
+
+impl<T: IndexTy> ToContextValue<T> for AlwaysNone {
+    fn to_context_value(self) -> Option<T> {
+        None
+    }
+}
+
+impl<T: IndexTy> ToContextValue<T> for T {
+    fn to_context_value(self) -> Option<T> {
+        Some(self)
+    }
+}
+
+impl<T: IndexTy> ToContextValue<T> for Option<T> {
+    fn to_context_value(self) -> Option<T> {
+        self
+    }
+}
+
+#[derive(Debug, Error)]
+pub struct WithContext<Block, Inst, Succ, Operand, BlockParam, E>
+where
+    Block: ToContextValue<BlockIdx>,
+    Inst: ToContextValue<InstIdx>,
+    Succ: ToContextValue<BlockIdx>,
+    Operand: ToContextValue<OperandIdx>,
+    BlockParam: ToContextValue<BlockParamIdx>,
+{
+    pub block: Block,
+    pub inst: Inst,
+    pub succ: Succ,
+    pub operand: Operand,
+    pub param: BlockParam,
+    #[source]
+    pub out_of_range_error: E,
+}
+
+impl<Block, Inst, Succ, Operand, BlockParam, E> fmt::Display
+    for WithContext<Block, Inst, Succ, Operand, BlockParam, E>
+where
+    Block: ToContextValue<BlockIdx>,
+    Inst: ToContextValue<InstIdx>,
+    Succ: ToContextValue<BlockIdx>,
+    Operand: ToContextValue<OperandIdx>,
+    BlockParam: ToContextValue<BlockParamIdx>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self {
+            block,
+            inst,
+            succ,
+            operand,
+            param,
+            out_of_range_error: _,
+        } = self;
+        let block = block.to_context_value();
+        let inst = inst.to_context_value();
+        let succ = succ.to_context_value();
+        let operand = operand.to_context_value();
+        let param = param.to_context_value();
+        macro_rules! write_if {
+            ($field:ident, $f:ident, $($rest:tt)+) => {
+                if let Some($field) = $field {
+                    write!($f, $($rest)+)?;
+                }
+            };
+        }
+        if block.is_some() || inst.is_some() {
+            write!(f, " in ")?;
+        }
+        write_if!(block, f, "{block}");
+        if block.is_some() && inst.is_some() {
+            write!(f, ":")?;
+        }
+        write_if!(inst, f, "{inst}");
+        write_if!(succ, f, " in successor {succ}");
+        write_if!(operand, f, " in {operand}");
+        write_if!(param, f, " in block parameter {param}");
+        Ok(())
+    }
+}
+
 #[derive(Debug, Error)]
 pub enum Error {
+    #[error(transparent)]
+    SSAValIdxOutOfRangeWithBlockInstAndOperand(
+        #[from]
+        WithContext<
+            Option<BlockIdx>,
+            InstIdx,
+            AlwaysNone,
+            OperandIdx,
+            AlwaysNone,
+            SSAValIdxOutOfRange,
+        >,
+    ),
+    #[error(transparent)]
+    SSAValIdxOutOfRangeWithBlockInstSuccAndParam(
+        #[from]
+        WithContext<
+            Option<BlockIdx>,
+            InstIdx,
+            BlockIdx,
+            AlwaysNone,
+            BlockParamIdx,
+            SSAValIdxOutOfRange,
+        >,
+    ),
+    #[error(transparent)]
+    SSAValIdxOutOfRangeWithBlockAndParam(
+        #[from]
+        WithContext<
+            BlockIdx,
+            AlwaysNone,
+            AlwaysNone,
+            AlwaysNone,
+            BlockParamIdx,
+            SSAValIdxOutOfRange,
+        >,
+    ),
+    #[error(transparent)]
+    InstIdxOutOfRangeWithBlock(
+        #[from]
+        WithContext<BlockIdx, AlwaysNone, AlwaysNone, AlwaysNone, AlwaysNone, InstIdxOutOfRange>,
+    ),
+    #[error(transparent)]
+    InstIdxOutOfRange(#[from] InstIdxOutOfRange),
+    #[error(transparent)]
+    BlockIdxOutOfRange(#[from] BlockIdxOutOfRange),
+    #[error(transparent)]
+    BlockParamIdxOutOfRangeWithBlock(
+        #[from]
+        WithContext<
+            BlockIdx,
+            AlwaysNone,
+            AlwaysNone,
+            AlwaysNone,
+            AlwaysNone,
+            BlockParamIdxOutOfRange,
+        >,
+    ),
+    #[error(transparent)]
+    BlockParamIdxOutOfRangeWithBlockInstAndSucc(
+        #[from]
+        WithContext<
+            Option<BlockIdx>,
+            InstIdx,
+            BlockIdx,
+            AlwaysNone,
+            AlwaysNone,
+            BlockParamIdxOutOfRange,
+        >,
+    ),
+    #[error(transparent)]
+    OperandIdxOutOfRangeWithBlockAndInst(
+        #[from]
+        WithContext<
+            Option<BlockIdx>,
+            InstIdx,
+            AlwaysNone,
+            AlwaysNone,
+            AlwaysNone,
+            OperandIdxOutOfRange,
+        >,
+    ),
     #[error("can't create a vector of an only-scalar type: {base_ty:?}")]
     TriedToCreateVectorOfOnlyScalarType { base_ty: BaseTy },
     #[error("reg_len out of range")]
@@ -49,16 +482,11 @@ pub enum Error {
     TermInstOnlyAllowedAtBlockEnd { inst_idx: InstIdx },
     #[error("instruction not in a block: {inst}")]
     InstHasNoBlock { inst: InstIdx },
-    #[error("operand index {operand_idx} out of range for {inst}")]
-    OperandIndexOutOfRange { inst: InstIdx, operand_idx: usize },
     #[error("duplicate copy destination operand: operand index {operand_idx} for {inst}")]
-    DupCopyDestOperand { inst: InstIdx, operand_idx: usize },
-    #[error("SSA value index {idx} out of range")]
-    SSAValIdxOutOfRange { idx: SSAValIdx },
-    #[error("instruction index {idx} out of range")]
-    InstIdxOutOfRange { idx: InstIdx },
-    #[error("block index {idx} out of range")]
-    BlockIdxOutOfRange { idx: BlockIdx },
+    DupCopyDestOperand {
+        inst: InstIdx,
+        operand_idx: OperandIdx,
+    },
     #[error("copy instruction's source type doesn't match source operands")]
     CopySrcTyMismatch { inst: InstIdx },
     #[error("copy instruction's destination type doesn't match destination operands")]
@@ -70,7 +498,7 @@ pub enum Error {
     MissingOperandUse {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
-        operand_idx: usize,
+        operand_idx: OperandIdx,
     },
     #[error(
         "operand index {operand_idx} for {inst} has kind `Def` but isn't \
@@ -79,7 +507,7 @@ pub enum Error {
     OperandDefIsNotSSAValDef {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
-        operand_idx: usize,
+        operand_idx: OperandIdx,
     },
     #[error(
         "SSA value {ssa_val_idx}'s definition isn't the corresponding \
@@ -88,7 +516,7 @@ pub enum Error {
     SSAValDefIsNotOperandsSSAVal {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
-        operand_idx: usize,
+        operand_idx: OperandIdx,
     },
     #[error(
         "SSA value {ssa_val_idx}'s type can't be used with the constraint on \
@@ -97,13 +525,16 @@ pub enum Error {
     ConstraintTyMismatch {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
-        operand_idx: usize,
+        operand_idx: OperandIdx,
     },
     #[error(
         "fixed location constraint on operand index {operand_idx} for \
         {inst} conflicts with clobbers"
     )]
-    FixedLocConflictsWithClobbers { inst: InstIdx, operand_idx: usize },
+    FixedLocConflictsWithClobbers {
+        inst: InstIdx,
+        operand_idx: OperandIdx,
+    },
     #[error("operand kind must be def")]
     OperandKindMustBeDef,
     #[error(
@@ -112,7 +543,7 @@ pub enum Error {
     )]
     ReuseTargetOperandMustBeUse {
         inst: InstIdx,
-        reuse_target_operand_idx: usize,
+        reuse_target_operand_idx: OperandIdx,
     },
     #[error(
         "source block {src_block} missing from branch {branch_inst}'s \
@@ -131,7 +562,7 @@ pub enum Error {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
         succ: BlockIdx,
-        param_idx: usize,
+        param_idx: BlockParamIdx,
     },
     #[error(
         "the number of parameters ({branch_param_count}) for branch {inst}'s \
@@ -152,7 +583,7 @@ pub enum Error {
     BranchSuccParamTyMismatch {
         inst: InstIdx,
         succ: BlockIdx,
-        param_idx: usize,
+        param_idx: BlockParamIdx,
         block_param_ty: Ty,
         branch_param_ty: Ty,
     },
@@ -163,7 +594,7 @@ pub enum Error {
     MismatchedBlockParamDef {
         ssa_val_idx: SSAValIdx,
         block: BlockIdx,
-        param_idx: usize,
+        param_idx: BlockParamIdx,
     },
     #[error(
         "predecessor {src_block} of target block {tgt_block} is missing from \
@@ -174,8 +605,6 @@ pub enum Error {
         branch_inst: InstIdx,
         tgt_block: BlockIdx,
     },
-    #[error("block parameter index {param_idx} is out of range for block {block}")]
-    BlockParamIdxOutOfRange { block: BlockIdx, param_idx: usize },
     #[error(
         "SSA value {ssa_val_idx}'s use isn't the corresponding \
         operand's SSA Value: operand index {operand_idx} for {inst}"
@@ -183,7 +612,7 @@ pub enum Error {
     SSAValUseIsNotOperandsSSAVal {
         ssa_val_idx: SSAValIdx,
         inst: InstIdx,
-        operand_idx: usize,
+        operand_idx: OperandIdx,
     },
     #[error(
         "SSA value {ssa_val_idx} is use as a branch instruction {inst}'s \
@@ -200,15 +629,6 @@ pub enum Error {
         branch_inst: InstIdx,
         tgt_block: BlockIdx,
     },
-    #[error(
-        "branch instruction {branch_inst}'s block parameter index {param_idx} \
-        is out of range for target block {tgt_block}"
-    )]
-    BranchTargetParamIdxOutOfRange {
-        branch_inst: InstIdx,
-        tgt_block: BlockIdx,
-        param_idx: usize,
-    },
     #[error(
         "SSA value {ssa_val_idx}'s use isn't the corresponding \
         branch {branch_inst}'s target block parameter's SSA Value for \
@@ -218,7 +638,7 @@ pub enum Error {
         ssa_val_idx: SSAValIdx,
         branch_inst: InstIdx,
         tgt_block: BlockIdx,
-        param_idx: usize,
+        param_idx: BlockParamIdx,
     },
     #[error(
         "block {block_idx} has incorrect immediate dominator: expected \
@@ -248,8 +668,8 @@ pub enum Error {
     )]
     ReuseOperandTyMismatch {
         inst: InstIdx,
-        tgt_operand_idx: usize,
-        src_operand_idx: usize,
+        tgt_operand_idx: OperandIdx,
+        src_operand_idx: OperandIdx,
         src_ty: Ty,
         tgt_ty: Ty,
     },