let rec gettype_binop op t1 t2 = match (op,t1,t2) with
    (Ast.SynBinopAndTyBoolTyBool-> TyBool
  | (Ast.SynBinopOrTyBoolTyBool-> TyBool
  | (Ast.SynBinopAddTyIntTyInt-> TyInt
  | (Ast.SynBinopSubTyIntTyInt-> TyInt
  | (Ast.SynBinopMulTyIntTyInt-> TyInt
  | (Ast.SynBinopDivTyIntTyInt-> TyFloat
  | (Ast.SynBinopIDivTyIntTyInt-> TyInt
  | (Ast.SynBinopModTyIntTyInt-> TyInt
  | (Ast.SynBinopAdd, (TyInt | TyFloat), TyFloat-> TyFloat
  | (Ast.SynBinopAddTyFloatTyInt-> TyFloat
  | (Ast.SynBinopSub, (TyInt | TyFloat), TyFloat-> TyFloat
  | (Ast.SynBinopSubTyFloatTyInt-> TyFloat
  | (Ast.SynBinopMul, (TyInt | TyFloat), TyFloat-> TyFloat
  | (Ast.SynBinopMulTyFloatTyInt-> TyFloat
  | (Ast.SynBinopDiv, (TyInt | TyFloat), TyFloat-> TyFloat
  | (Ast.SynBinopDivTyFloatTyInt-> TyFloat
  | (Ast.SynBinopConcatTyStringTyString-> TyString
  | (Ast.SynBinopConcatTyList t_list1, TyList t_list2) when (t_list1 = t_list2) -> TyList t_list1
  | (Ast.SynBinopCons, t_item, TyList t_list) when (t_item = t_list) -> TyList t_list
  | (Ast.SynCompLt, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompGt, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompLte, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompGte, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompEq, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompNeq, (TyInt | TyFloat), (TyInt | TyFloat)) -> TyBool
  | (Ast.SynCompEq, x, y) when (x = y) -> TyBool
  | (Ast.SynCompNeq, x, y) when (x = y) -> TyBool
  | _ -> raise_type_error ["Attempted to perform an invalid binary operation ";Ast.string_of_binop op;" on values of type ";string_of_type t1;" and ";string_of_type t2]