/
type_overloading.ml
137 lines (126 loc) · 5.27 KB
/
type_overloading.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
open Ast.Ast_types
open Parsing
open Core
open Type_env
open Type_inheritance
let string_of_args_types = function
| [] -> string_of_type TEVoid
| _ as args_types -> String.concat ~sep:" * " (List.map ~f:string_of_type args_types)
(* Check overloaded function and method definitions *)
let type_overloaded_params error_prefix params_list =
if
not
(List.contains_dup
~compare:(fun params1 params2 ->
List.compare
(fun (TParam (type_1, _, _, _)) (TParam (type_2, _, _, _)) ->
if type_1 = type_2 then 0 else 1)
params1 params2)
params_list)
then Ok ()
else
Error
(Error.of_string
(Fmt.str "%s has duplicate definitions in environment@." error_prefix))
let type_overloaded_func_name func_name function_defns =
let overloaded_function_params =
List.filter_map
~f:(fun (Parsed_ast.TFunction (name, _, _, params, _)) ->
if func_name = name then Some params else None)
function_defns in
let error_prefix =
Fmt.str "Type error - function %s" (Function_name.to_string func_name) in
type_overloaded_params error_prefix overloaded_function_params
let type_overloaded_function_defns function_defns =
let distinct_func_names =
List.map
~f:(fun (Parsed_ast.TFunction (func_name, _, _, _, _)) -> func_name)
function_defns in
Result.all_unit
(List.map
~f:(fun func_name -> type_overloaded_func_name func_name function_defns)
distinct_func_names)
let type_overloaded_method_name method_name function_defns =
let overloaded_method_params =
List.filter_map
~f:(fun (Parsed_ast.TMethod (name, _, _, params, _, _)) ->
if method_name = name then Some params else None)
function_defns in
let error_prefix =
Fmt.str "Type error - method %s" (Method_name.to_string method_name) in
type_overloaded_params error_prefix overloaded_method_params
let type_overloaded_method_defns method_defns =
let distinct_method_names =
List.map
~f:(fun (Parsed_ast.TMethod (method_name, _, _, _, _, _)) -> method_name)
method_defns in
Result.all_unit
(List.map
~f:(fun method_name -> type_overloaded_method_name method_name method_defns)
distinct_method_names)
(* Return matching param and return types for function / method calls, based on arg types *)
let get_matching_params_and_ret_type class_defns error_prefix params_and_ret_types
args_types =
match params_and_ret_types with
| [] ->
Error (Error.of_string (Fmt.str "%s is not defined in environment@." error_prefix))
| [(param_types, return_type)] (* function not overloaded *) ->
if are_subtypes_of class_defns args_types param_types then
Ok (param_types, return_type)
else
Error
(Error.of_string
(Fmt.str "%s expected arguments of type %s, instead received type %s@."
error_prefix
(string_of_args_types param_types)
(string_of_args_types args_types)))
| _ -> (
List.find ~f:(fun (param_types, _) -> args_types = param_types) params_and_ret_types
|> function
| Some params_and_ret_type -> Ok params_and_ret_type
| None -> (
List.filter
~f:(fun (param_types, _) ->
are_subtypes_of class_defns args_types param_types)
params_and_ret_types
|> function
| [] ->
Error
(Error.of_string
(Fmt.str "%s has no matching definition that accepts args of type %s@."
error_prefix
(string_of_args_types args_types)))
| [params_and_ret_types] -> Ok params_and_ret_types
| _ ->
Error
(Error.of_string
(Fmt.str
"%s has multiple matching definition that accepts args of type %s@."
error_prefix
(string_of_args_types args_types))) ) )
let get_matching_function_type class_defns func_name args_types function_defns loc =
let overloaded_function_param_and_ret_types =
List.filter_map
~f:(fun (Parsed_ast.TFunction (name, _, return_type, params, _)) ->
if func_name = name then Some (get_params_types params, return_type) else None)
function_defns in
let error_prefix =
Fmt.str "%s Type error - function %s" (string_of_loc loc)
(Function_name.to_string func_name) in
get_matching_params_and_ret_type class_defns error_prefix
overloaded_function_param_and_ret_types args_types
let get_matching_method_type class_defns method_name args_types curr_class_defn
maybe_type_param loc =
let open Result in
get_class_methods class_defns curr_class_defn maybe_type_param loc
>>= fun method_defns ->
List.filter_map
~f:(fun (Parsed_ast.TMethod (name, _, return_type, params, _, _)) ->
if method_name = name then Some (get_params_types params, return_type) else None)
method_defns
|> fun overloaded_method_param_and_ret_types ->
let error_prefix =
Fmt.str "%s Type error - method %s" (string_of_loc loc)
(Method_name.to_string method_name) in
get_matching_params_and_ret_type class_defns error_prefix
overloaded_method_param_and_ret_types args_types