typecheck.ml 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. (*
  2. * Do a number of checks:
  3. * - A void function must not return a value.
  4. * - A non-void function must return a value of the correct type.
  5. * - Array indices must be of type integer.
  6. * - The number of array indices must match the number of array dimensions.
  7. * - The type on the right-hand side of an assignment must match the type on
  8. * the left-hand side.
  9. * - The number of arguments used for a function call must match the number of
  10. * parameters for that function.
  11. * - The types of the function arguments must match the types of parameters.
  12. * - The operands of a unary or binary operation must have valid types.
  13. * - The predicate expression of an if, while, or do-while statement must be
  14. * a boolean.
  15. * - Only values of a basic type can be type cast.
  16. *)
  17. open Printf
  18. open Types
  19. open Util
  20. open Stringify
  21. let node_error (node, msg) = FatalError (NodeMsg (node, msg))
  22. (* Stringify a list of types for use in error messages.
  23. * ctype list -> string *)
  24. let rec types2str = function
  25. | [] -> ""
  26. | [ctype] -> type2str ctype
  27. | ctype :: tail -> type2str ctype ^ " or " ^ (types2str tail)
  28. let array_depth = function
  29. | ArrayDims (_, dims) -> List.length dims
  30. | _ -> raise InvalidNode
  31. let spec = function
  32. | ArrayDims (ctype, dims) -> (ctype, List.length dims)
  33. | ctype -> (ctype, 0)
  34. let type2str_error = function
  35. | ArrayDims (ctype, dims) ->
  36. type2str ctype ^ "[" ^ repeat "," (List.length dims - 1) ^ "]"
  37. | ctype ->
  38. type2str ctype
  39. let check_type ?(msg="") expected node =
  40. let got = typeof node in
  41. if expected <> Unknown && got <> Unknown && (spec got) <> (spec expected)
  42. then begin
  43. let msg = match msg with
  44. | "" -> sprintf "type mismatch: expected type %s, got %s"
  45. (type2str_error expected) (type2str_error got)
  46. | _ -> msg
  47. in
  48. [NodeMsg (node, msg)]
  49. end
  50. else []
  51. let op_types = function
  52. | Not | And | Or -> [Bool]
  53. | Mod -> [Int]
  54. | Neg | Sub | Div | Lt | Le | Gt | Ge -> [Int; Float]
  55. | Add | Mul | Eq | Ne -> [Bool; Int; Float]
  56. let op_result_type opnd_type = function
  57. | Not | And | Or | Eq | Ne | Lt | Le | Gt | Ge -> Bool
  58. | Neg | Add | Sub | Mul | Div | Mod -> opnd_type
  59. (* Check if the given operator can be applied to the given type *)
  60. let check_type_op allowed_types desc node =
  61. let got = typeof node in
  62. if got <> Unknown && not (List.mem got allowed_types)
  63. then
  64. [NodeMsg (node, sprintf
  65. "%s cannot be applied to type %s, only to %s"
  66. desc (type2str got) (types2str allowed_types))]
  67. else
  68. []
  69. let check_dims_match dims dec_type errnode =
  70. match (List.length dims, array_depth dec_type) with
  71. | (got, expected) when got != expected ->
  72. let msg = sprintf
  73. "dimension mismatch: expected %d indices, got %d"
  74. expected got
  75. in
  76. [NodeMsg (errnode, msg)]
  77. | _ -> []
  78. let err_map f nodes =
  79. let n, e = List.split (List.map f nodes) in
  80. (n, List.concat e)
  81. let default_unknown ctype = function [] -> ctype | _ -> Unknown
  82. let rec typecheck node =
  83. let add_error node msg =
  84. let node, err = traverse_list typecheck node in
  85. (annotate (Type Unknown) node, NodeMsg (node, msg) :: err)
  86. in
  87. let check_trav ctype node =
  88. let node, err = typecheck node in
  89. (node, err @ check_type ctype node)
  90. in
  91. match node with
  92. | FunUse ((FunDec (ret_type, name, params, _) as dec), args, ann)
  93. | FunUse ((FunDef (_, ret_type, name, params, _, _) as dec), args, ann) ->
  94. begin
  95. match (List.length args, List.length params) with
  96. | (nargs, nparams) when nargs != nparams ->
  97. add_error node (sprintf
  98. "function \"%s\" expects %d arguments, got %d"
  99. name nparams nargs)
  100. | _ ->
  101. let args, aerr = err_map typecheck args in
  102. let check_arg_type arg param = check_type (typeof param) arg in
  103. let err = List.concat (List.map2 check_arg_type args params) in
  104. (FunUse (dec, args, Type ret_type :: ann), aerr @ err)
  105. end
  106. (* Operators match operand types and get a new type based on the operator *)
  107. | Monop (op, opnd, ann) ->
  108. let opnd, oerr = typecheck opnd in
  109. let desc = sprintf "unary operator \"%s\"" (op2str op) in
  110. let err = check_type_op (op_types op) desc opnd in
  111. let res_type = default_unknown (typeof opnd) err in
  112. (Monop (op, opnd, Type (op_result_type res_type op) :: ann),
  113. oerr @ err)
  114. | Binop (op, left, right, ann) ->
  115. let left, lerr = typecheck left in
  116. let right, rerr = typecheck right in
  117. let desc = sprintf "binary operator \"%s\"" (op2str op) in
  118. let err =
  119. (* Only compare operand types if left operand has a valid type *)
  120. match check_type_op (op_types op) desc left with
  121. | [] -> check_type (typeof left) right
  122. | err -> err
  123. in
  124. let res_type = default_unknown (typeof left) err in
  125. (* Check for division by zero *)
  126. begin
  127. match (op, right) with
  128. | (Div, Const (IntVal 0l, _)) ->
  129. node_warning right "division by zero"
  130. | _ -> ()
  131. end;
  132. (Binop (op, left, right, Type (op_result_type res_type op) :: ann),
  133. lerr @ rerr @ err)
  134. (* Conditions must be bool, and right-hand type must match left-hand type *)
  135. | Cond (cond, texpr, fexpr, ann) ->
  136. let cond, cerr = check_trav Bool cond in
  137. let texpr, terr = typecheck texpr in
  138. let fexpr, ferr = check_trav (typeof texpr) fexpr in
  139. (Cond (cond, texpr, fexpr, Type (typeof texpr) :: ann), cerr @ terr @ ferr)
  140. (* Only basic types can be typecasted *)
  141. | TypeCast (ctype, value, ann) ->
  142. let value, err = typecheck value in
  143. let err = err @ check_type_op [Bool; Int; Float] "typecast" value in
  144. (TypeCast (ctype, value, Type ctype :: ann), err)
  145. (* Array allocation dimensions must have type int *)
  146. | Allocate (dec, dims, ann) ->
  147. let dims, err = err_map typecheck dims in
  148. let err = err @ List.concat (List.map (check_type Int) dims) in
  149. (Allocate (dec, dims, ann), err)
  150. (* Array dimensions are always integers *)
  151. | Dim (name, ann) ->
  152. (Dim (name, Type Int :: ann), [])
  153. (* Void functions may have a return statement without a value, other functions
  154. * must have a return statement of a valid type *)
  155. | FunDef (export, ret_type, name, params, body, ann) ->
  156. let params, perr = err_map typecheck params in
  157. let body, berr = typecheck body in
  158. let rec check_types = function
  159. | Return (Some _, _) as ret when ret_type = Void ->
  160. ret, [NodeMsg (ret, "void function should not have a return value")]
  161. | Return (Some value, _) as ret when typeof value <> ret_type ->
  162. ret, [NodeMsg (ret, sprintf
  163. "function \"%s\" has return type %s, got %s"
  164. name (type2str ret_type) (type2str (typeof value)))]
  165. | node -> traverse_list check_types node
  166. in
  167. let err =
  168. snd (check_types body) @
  169. match last_if_return body with
  170. | None when ret_type <> Void ->
  171. [NodeMsg (node, sprintf
  172. "function \"%s\" must end with a return of type %s"
  173. (type2str ret_type) name)]
  174. | _ -> []
  175. in
  176. (FunDef (export, ret_type, name, params, body, ann), perr @ berr @ err)
  177. (* Conditions in must have type bool *)
  178. | If (cond, body, ann) ->
  179. let cond, cerr = check_trav Bool cond in
  180. let body, berr = typecheck body in
  181. (If (cond, body, ann), cerr @ berr)
  182. | IfElse (cond, tbody, fbody, ann) ->
  183. let cond, cerr = check_trav Bool cond in
  184. let tbody, terr = typecheck tbody in
  185. let fbody, ferr = typecheck fbody in
  186. (IfElse (cond, tbody, fbody, ann), cerr @ terr @ ferr)
  187. | While (cond, body, ann) ->
  188. let cond, cerr = check_trav Bool cond in
  189. let body, berr = typecheck body in
  190. (While (cond, body, ann), cerr @ berr)
  191. | DoWhile (cond, body, ann) ->
  192. let body, berr = typecheck body in
  193. let cond, cerr = check_trav Bool cond in
  194. (DoWhile (cond, body, ann), berr @ cerr)
  195. (* Constants *)
  196. | Const (BoolVal value, ann) ->
  197. (Const (BoolVal value, Type Bool :: ann), [])
  198. | Const (IntVal value, ann) ->
  199. (Const (IntVal value, Type Int :: ann), [])
  200. | Const (FloatVal value, ann) ->
  201. (Const (FloatVal value, Type Float :: ann), [])
  202. (* Variables inherit the type of their declaration *)
  203. | VarUse (dec, None, ann) ->
  204. (VarUse (dec, None, Type (typeof dec) :: ann), [])
  205. | VarUse (dec, Some dims, ann) ->
  206. (* Dimensions must have int type *)
  207. let dims, err = err_map typecheck dims in
  208. let err = err @ List.concat (List.map (check_type Int) dims) in
  209. (* Number of indices must match number of array dimensions *)
  210. let err = err @ check_dims_match dims (typeof dec) node in
  211. (VarUse (dec, Some dims, Type (basetypeof dec) :: ann), err)
  212. (* Array pointers cannot be re-assigned, because array dimension reduction
  213. * makes assumptions about dimensions of an array *)
  214. | VarLet (dec, None, _, _) when is_array dec ->
  215. add_error node "cannot assign value to array pointer after initialisation"
  216. (* Assigned values must match variable declaration *)
  217. | VarLet (dec, None, value, ann) as node ->
  218. let value, err = typecheck value in
  219. let err = err @ check_type (typeof dec) value in
  220. (VarLet (dec, None, value, ann), err)
  221. | VarLet (dec, Some dims, value, ann) ->
  222. (* Number of indices must match number of array dimensions *)
  223. let err1 = check_dims_match dims (typeof dec) node in
  224. (* Array indices must be ints *)
  225. let dims, err2 = err_map typecheck dims in
  226. let err2 = err2 @ List.concat (List.map (check_type Int) dims) in
  227. (* Assigned value must match array base type *)
  228. let value, err3 = typecheck value in
  229. let err3 = err3 @ check_type (basetypeof dec) value in
  230. (VarLet (dec, Some dims, value, ann), err1 @ err2 @ err3)
  231. (* ArrayConst initialisations are transformed during desugaring, so any
  232. * occurrences that are left are illegal *)
  233. | ArrayConst _ ->
  234. add_error node "array constants can only be used in array initialisation"
  235. | _ -> traverse_list typecheck node
  236. let phase = function
  237. | Ast node ->
  238. let node, err = typecheck node in
  239. Ast (quit_on_error err node)
  240. | _ -> raise InvalidInput