diff options
| -rw-r--r-- | bytecomp/translclass.ml | 57 | ||||
| -rw-r--r-- | bytecomp/translcore.ml | 7 | ||||
| -rw-r--r-- | parsing/parser.mly | 146 | ||||
| -rw-r--r-- | parsing/parsetree.mli | 8 | ||||
| -rw-r--r-- | stdlib/oo.ml | 81 | ||||
| -rw-r--r-- | stdlib/oo.mli | 7 | ||||
| -rw-r--r-- | testobjects/Exemples.exp | 64 | ||||
| -rw-r--r-- | testobjects/Tests.exp | 14 | ||||
| -rw-r--r-- | testobjects/Tests.ml | 14 | ||||
| -rw-r--r-- | tools/ocamlprof.ml | 4 | ||||
| -rw-r--r-- | toplevel/genprintval.ml | 2 | ||||
| -rw-r--r-- | typing/btype.ml | 6 | ||||
| -rw-r--r-- | typing/btype.mli | 4 | ||||
| -rw-r--r-- | typing/includecore.ml | 31 | ||||
| -rw-r--r-- | typing/printtyp.ml | 54 | ||||
| -rw-r--r-- | typing/subst.ml | 15 | ||||
| -rw-r--r-- | typing/typeclass.ml | 333 | ||||
| -rw-r--r-- | typing/typecore.ml | 62 | ||||
| -rw-r--r-- | typing/typecore.mli | 4 | ||||
| -rw-r--r-- | typing/typedtree.ml | 10 | ||||
| -rw-r--r-- | typing/typedtree.mli | 10 | ||||
| -rw-r--r-- | typing/types.ml | 16 | ||||
| -rw-r--r-- | typing/types.mli | 16 | ||||
| -rw-r--r-- | typing/typetexp.ml | 2 |
24 files changed, 625 insertions, 342 deletions
diff --git a/bytecomp/translclass.ml b/bytecomp/translclass.ml index bb3882c365..856bf22689 100644 --- a/bytecomp/translclass.ml +++ b/bytecomp/translclass.ml @@ -22,17 +22,23 @@ open Translcore let transl_label l = Lconst (Const_base (Const_string l)) +let rec transl_meth_list = + function + [] -> Const_pointer 0 + | lab::rem -> Const_block (0, [Const_base (Const_string lab); + transl_meth_list rem]) + (* Instance variable initialization *) let set_inst_var obj var id expr = Lprim(Parraysetu (if maybe_pointer expr then Paddrarray else Pintarray), [Lvar obj; Lvar id; transl_exp expr]) -let transl_super tbl inh_methods rem = +let transl_super tbl meths inh_methods rem = List.fold_right (fun (nm, id) rem -> Llet(StrictOpt, id, Lapply (oo_prim "get_method", - [Lvar tbl; Lvar (meth nm)]), + [Lvar tbl; Lvar (Meths.find nm meths)]), rem)) inh_methods rem @@ -58,9 +64,16 @@ let inherited_values vals = Const_block(0, [Const_base (Const_string v); rem])) vals (Const_pointer 0)) +let inherited_meths methods = + Lconst + (List.fold_right + (fun v rem -> + Const_block(0, [Const_base (Const_string v); rem])) + methods (Const_pointer 0)) + let transl_field_obj obj field (obj_init, anc_id) = match field with - Cf_inher (name, args, vals, meths) -> + Cf_inher (name, args, vals, inh_meths, meths') -> let init = Ident.create "init" in (Lsequence(Lapply(Lvar init, Lvar obj :: (List.map transl_exp args)), obj_init), @@ -73,13 +86,15 @@ let transl_field_obj obj field (obj_init, anc_id) = | Cf_meth (name, exp) -> (obj_init, anc_id) -let transl_field_cl tbl field cl_init = +let transl_field_cl tbl meths field cl_init = match field with - Cf_inher (name, args, vals, meths) -> - Lsequence(Lapply (oo_prim "inheritance", [Lvar tbl; transl_path name; - inherited_values vals]), + Cf_inher (name, args, vals, inh_meths, meths') -> + Lsequence(Lapply (oo_prim "inheritance", + [Lvar tbl; transl_path name; + inherited_values vals; + inherited_meths meths']), transl_vals tbl vals ( - transl_super tbl meths cl_init)) + transl_super tbl meths inh_meths cl_init)) | Cf_val (name, id, priv, exp) -> if priv = Private then transl_private_val tbl name id cl_init @@ -87,7 +102,7 @@ let transl_field_cl tbl field cl_init = transl_val tbl name id cl_init | Cf_meth (name, exp) -> Lsequence(Lapply (oo_prim "set_method", - [Lvar tbl; Lvar (meth name); transl_exp exp]), + [Lvar tbl; transl_label name; transl_exp exp]), cl_init) let transl_val_hiding tbl cl_init = @@ -99,7 +114,27 @@ let transl_val_hiding tbl cl_init = [Lvar tbl; transl_label name]), cl_init) +let bind_methods tbl public_methods lab id cl_init = + if List.mem lab public_methods then + Llet(Alias, id, Lvar (meth lab), cl_init) + else + Llet(StrictOpt, id, Lapply (oo_prim "get_method_label", + [Lvar tbl; transl_label lab]), + cl_init) + +let transl_fields tbl public_methods meths fields cl_init = + match fields with + Cf_inher _ as inh :: fields -> + transl_field_cl tbl meths inh + (Meths.fold (bind_methods tbl public_methods) meths + (List.fold_right (transl_field_cl tbl meths) fields cl_init)) + | fields -> + Meths.fold (bind_methods tbl public_methods) meths + (List.fold_right (transl_field_cl tbl meths) fields cl_init) + + let transl_class cl_id cl = + let public_methods = Lconst (transl_meth_list cl.cl_pub_meths) in let obj = Ident.create "obj" in let (field_init, anc_id) = List.fold_right (transl_field_obj obj) cl.cl_field (Lvar obj, []) @@ -118,12 +153,12 @@ let transl_class cl_id cl = let cl_init = Lfunction (Curried, [table], List.fold_left (transl_val_hiding table) - (List.fold_right (transl_field_cl table) cl.cl_field + (transl_fields table cl.cl_pub_meths cl.cl_meths cl.cl_field (Lapply (oo_prim "set_initializer", [Lvar table; obj_init]))) cl.cl_field) in - Lapply (oo_prim "create_class", [Lvar cl_id; cl_init]) + Lapply (oo_prim "create_class", [Lvar cl_id; public_methods; cl_init]) let class_stub = Lprim(Pmakeblock(0, Mutable), [lambda_unit; lambda_unit; lambda_unit]) diff --git a/bytecomp/translcore.ml b/bytecomp/translcore.ml index 71c65ec7bc..bbb23821a6 100644 --- a/bytecomp/translcore.ml +++ b/bytecomp/translcore.ml @@ -480,7 +480,12 @@ let rec transl_exp e = (Lifthenelse(transl_exp cond, event_before body (transl_exp body), Lstaticfail)) | Texp_send(expr, met) -> - event_after e (Lsend(Lvar (meth met), transl_exp expr, [])) + let met_id = + match met with + Tmeth_name nm -> meth nm + | Tmeth_val id -> id + in + event_after e (Lsend(Lvar met_id, transl_exp expr, [])) | Texp_new cl -> Lprim(Pfield 0, [transl_path cl]) | Texp_instvar(path_self, path) -> diff --git a/parsing/parser.mly b/parsing/parser.mly index 6973c3407a..b8721c19a5 100644 --- a/parsing/parser.mly +++ b/parsing/parser.mly @@ -202,7 +202,7 @@ let rec mkrangepat c1 c2 = %right prec_unary_minus /* - unary */ %left prec_appl /* function application */ %right prec_constr_appl /* constructor application */ -%left SHARP /* method call */ +%left SHARP /* method call */ %left DOT DOTLPAREN DOTLBRACKET /* record access, array access */ %right PREFIXOP /* ! */ @@ -652,20 +652,20 @@ primitive_declaration: /* Class definitions */ class_list: - class_list AND class_def + class_list AND class_def { $3 :: $1 } | class_def - { [$1] } + { [$1] } ; class_def: virtual_flag closed_flag - class_type_parameters LIDENT simple_pattern_list self self_type EQUAL + class_type_parameters LIDENT simple_pattern_list self self_type EQUAL constraints class_fields - { { pcl_name = $4; pcl_param = $3; pcl_args = List.rev $5; - pcl_self = $6; pcl_self_ty = $7; pcl_cstr = List.rev $9; - pcl_field = List.rev $10; - pcl_kind = $1; pcl_closed = $2; - pcl_loc = symbol_loc () } } + { { pcl_name = $4; pcl_param = $3; pcl_args = List.rev $5; + pcl_self = $6; pcl_self_ty = $7; pcl_cstr = List.rev $9; + pcl_field = List.rev $10; + pcl_kind = $1; pcl_closed = $2; + pcl_loc = symbol_loc () } } ; class_type_parameters: type_parameters @@ -675,122 +675,122 @@ simple_pattern_list: simple_pattern { [$1] } | simple_pattern_list simple_pattern - { $2::$1 } + { $2::$1 } ; self: - AS LIDENT - { Some $2 } + AS LIDENT + { Some $2 } | /* empty */ - { None } + { None } ; class_fields: /* empty */ - { [] } + { [] } | class_fields INHERIT ancestor - { Pcf_inher $3 :: $1 } + { Pcf_inher $3 :: $1 } | class_fields VAL value - { Pcf_val $3 :: $1 } - | class_fields VIRTUAL method_type - { Pcf_virt $3 :: $1 } - | class_fields METHOD method_def - { Pcf_meth $3 :: $1 } + { Pcf_val $3 :: $1 } + | class_fields virtual_method + { Pcf_virt $2 :: $1 } + | class_fields method_def + { Pcf_meth $2 :: $1 } ; ancestor: LPAREN core_type_comma_list RPAREN class_longident simple_expr_list - self + self { $4, List.rev $2, List.rev $5, $6, symbol_loc () } | LPAREN core_type RPAREN class_longident simple_expr_list self - { $4, [$2], List.rev $5, $6, symbol_loc () } + { $4, [$2], List.rev $5, $6, symbol_loc () } | class_longident simple_expr_list self - { $1, [], List.rev $2, $3, symbol_loc () } + { $1, [], List.rev $2, $3, symbol_loc () } ; value: private_flag mutable_flag label EQUAL expr - { $3, $1, $2, Some $5, symbol_loc () } + { $3, $1, $2, Some $5, symbol_loc () } | private_flag mutable_flag label - { $3, $1, $2, None, symbol_loc () } + { $3, $1, $2, None, symbol_loc () } ; +virtual_method: + private_flag VIRTUAL label COLON core_type + { $3, $1, $5, symbol_loc () } + method_def : - label fun_binding - { $1, $2, symbol_loc () } + private_flag METHOD label fun_binding + { $3, $1, $4, symbol_loc () } ; /* Class type definitions */ class_type_list: - class_type_list AND class_type + class_type_list AND class_type { $3 :: $1 } | class_type - { [$1] } + { [$1] } ; class_type: virtual_flag closed_flag class_type_parameters LIDENT type_list self_type - EQUAL + EQUAL constraints class_type_fields - { { pcty_name = $4; pcty_param = $3; pcty_args = $5; - pcty_self = $6; pcty_cstr = List.rev $8; + { { pcty_name = $4; pcty_param = $3; pcty_args = $5; + pcty_self = $6; pcty_cstr = List.rev $8; pcty_field = List.rev $9; - pcty_kind = $1; pcty_closed = $2; - pcty_loc = symbol_loc () } } + pcty_kind = $1; pcty_closed = $2; + pcty_loc = symbol_loc () } } ; type_list: - LPAREN core_type RPAREN type_list - { $2 :: $4 } + LPAREN core_type RPAREN type_list + { $2 :: $4 } | LPAREN core_type RPAREN - { [$2] } + { [$2] } ; self_type: - COLON type_parameter - { Some $2 } + COLON type_parameter + { Some $2 } | /* empty */ - { None } + { None } ; constraints: - constraints CONSTRAINT constrain - { $3 :: $1 } + constraints CONSTRAINT constrain + { $3 :: $1 } | /* empty */ - { [] } + { [] } ; constrain: - type_parameter EQUAL core_type - { $1, $3, symbol_loc () } + type_parameter EQUAL core_type + { $1, $3, symbol_loc () } ; class_type_fields: /* empty */ - { [] } + { [] } | class_type_fields INHERIT ancestor_type - { Pctf_inher $3 :: $1 } + { Pctf_inher $3 :: $1 } | class_type_fields VAL value_type - { Pctf_val $3 :: $1 } - | class_type_fields VIRTUAL method_type - { Pctf_virt $3 :: $1 } - | class_type_fields METHOD method_type_opt - { Pctf_meth $3 :: $1 } + { Pctf_val $3 :: $1 } + | class_type_fields virtual_method + { Pctf_virt $2 :: $1 } + | class_type_fields method_type + { Pctf_meth $2 :: $1 } ; ancestor_type: LPAREN core_type_comma_list RPAREN class_longident { $4, List.rev $2, symbol_loc () } | LPAREN core_type RPAREN class_longident - { $4, [$2], symbol_loc () } + { $4, [$2], symbol_loc () } | class_longident - { $1, [], symbol_loc () } + { $1, [], symbol_loc () } ; value_type : private_flag mutable_flag label COLON core_type - { $3, $1, $2, Some $5, symbol_loc () } + { $3, $1, $2, Some $5, symbol_loc () } | private_flag mutable_flag label - { $3, $1, $2, None, symbol_loc () } + { $3, $1, $2, None, symbol_loc () } ; method_type : - label COLON core_type - { $1, $3, symbol_loc () } -; -method_type_opt : - label COLON core_type - { $1, Some $3, symbol_loc () } - | label - { $1, None, symbol_loc () } + private_flag METHOD label COLON core_type + { $3, $1, $5, symbol_loc () } + | private_flag METHOD label + { $3, $1, mktyp(Ptyp_any), symbol_loc () } ; /* Type declarations */ @@ -1030,7 +1030,7 @@ mty_longident: ; class_longident: LIDENT { Lident $1 } - | mod_longident DOT LIDENT { Ldot($1, $3) } + | mod_longident DOT LIDENT { Ldot($1, $3) } ; /* Toplevel directives */ @@ -1053,23 +1053,23 @@ direction_flag: | DOWNTO { Downto } ; private_flag: - /* empty */ { Public } - | PRIVATE { Private } + /* empty */ { Public } + | PRIVATE { Private } ; mutable_flag: /* empty */ { Immutable } | MUTABLE { Mutable } ; virtual_flag: - /* empty */ { Concrete } - | VIRTUAL { Virtual } + /* empty */ { Concrete } + | VIRTUAL { Virtual } ; closed_flag: - /* empty */ { Open } - | CLOSED { Closed } + /* empty */ { Open } + | CLOSED { Closed } ; opt_bar: - /* empty */ { () } - | BAR { () } + /* empty */ { () } + | BAR { () } ; %% diff --git a/parsing/parsetree.mli b/parsing/parsetree.mli index 7b57b7cc23..1f6ed64706 100644 --- a/parsing/parsetree.mli +++ b/parsing/parsetree.mli @@ -113,8 +113,8 @@ type class_type_field = Pctf_inher of (Longident.t * core_type list * Location.t) | Pctf_val of (string * private_flag * mutable_flag * core_type option * Location.t) - | Pctf_virt of (string * core_type * Location.t) - | Pctf_meth of (string * core_type option * Location.t) + | Pctf_virt of (string * private_flag * core_type * Location.t) + | Pctf_meth of (string * private_flag * core_type * Location.t) type class_type = { pcty_name: string; @@ -132,8 +132,8 @@ type class_field = string option * Location.t) | Pcf_val of (string * private_flag * mutable_flag * expression option * Location.t) - | Pcf_virt of (string * core_type * Location.t) - | Pcf_meth of (string * expression * Location.t) + | Pcf_virt of (string * private_flag * core_type * Location.t) + | Pcf_meth of (string * private_flag * expression * Location.t) type class_def = { pcl_name: string; diff --git a/stdlib/oo.ml b/stdlib/oo.ml index bfdb189fec..ef7c947920 100644 --- a/stdlib/oo.ml +++ b/stdlib/oo.ml @@ -27,7 +27,7 @@ let bucket_small_size = ref 16 let step = Sys.word_size / 16 -let first_label = 0 +let first_bucket = 0 let bucket_size = 32 (* Must be 256 or less *) @@ -172,6 +172,8 @@ let compact_buckets buckets = (**** Labels ****) +let first_label = first_bucket * 65536 * step + let last_label = ref first_label let methods = Hashtbl.create 101 @@ -188,15 +190,23 @@ let new_method met = Hashtbl.add methods met label; label +let new_anonymous_method = + new_label + (**** Sparse array ****) module Vars = Map.Make(struct type t = string let compare = compare end) type vars = int Vars.t +module Meths = Map.Make(struct type t = string let compare = compare end) +type meths = label list Meths.t + type obj_init type table = { mutable buckets: bucket array; - mutable methods: (label * item) list; + mutable methods: meths; + mutable saved_methods: meths list; + mutable meth_defs: (label * item) list; mutable vars: vars; mutable saved_vars: vars list; mutable saved_var_lst: int option list; @@ -210,7 +220,9 @@ let initial_size = 1 let new_table () = incr table_count; { buckets = [| |]; - methods = []; + methods = Meths.empty; + saved_methods = []; + meth_defs = []; vars = Vars.empty; saved_vars = []; saved_var_lst = []; @@ -221,6 +233,8 @@ let copy_table array1 array2 = incr version; array1.buckets <- Array.copy array2.buckets; array1.methods <- array2.methods; + array1.saved_methods <- []; + array1.meth_defs <- array2.meth_defs; array1.vars <- array2.vars; array1.saved_vars <- []; array1.saved_var_lst <- array1.saved_var_lst; @@ -250,7 +264,7 @@ let put array label element = (!bucket.(elem) != dummy_item) then begin if !clean_when_copying then - bucket := new_filled_bucket buck array.methods + bucket := new_filled_bucket buck array.meth_defs else bucket := copy_bucket !bucket; array.buckets.(buck) <- !bucket @@ -278,10 +292,11 @@ let set_initializer table init = | _ -> invalid_arg "Fatal error in Oo.set_initializer." -let inheritance table cl vars = +let inheritance table cl vars meths = if - !copy_parent & (table.methods = []) & (table.size = initial_size) - & (table.init = [[]; []]) + !copy_parent + && (table.methods = Meths.empty) && (table.size = initial_size) + && (table.init = [[]; []]) then begin copy_table table cl.table; table.init <- table.init@[[]]; @@ -290,7 +305,13 @@ let inheritance table cl vars = (fun s v -> try Vars.add v (Vars.find v table.vars) s with Not_found -> s) Vars.empty - vars + vars; + table.methods <- + List.fold_left + (fun s m -> + try Meths.add m (Meths.find m table.methods) s with Not_found -> s) + Meths.empty + meths end else begin table.init <- []::table.init; table.saved_vars <- table.vars::table.saved_vars; @@ -300,6 +321,13 @@ let inheritance table cl vars = try Vars.add v (Vars.find v table.vars) s with Not_found -> s) Vars.empty vars; + table.saved_methods <- table.methods::table.saved_methods; + table.methods <- + List.fold_left + (fun s m -> + try Meths.add m (Meths.find m table.methods) s with Not_found -> s) + Meths.empty + meths; cl.class_init table; table.vars <- List.fold_left @@ -307,12 +335,33 @@ let inheritance table cl vars = try Vars.add v (Vars.find v table.vars) s with Not_found -> s) (List.hd table.saved_vars) vars; - table.saved_vars <- List.tl table.saved_vars + table.saved_vars <- List.tl table.saved_vars; + table.methods <- + List.fold_left + (fun s m -> + try Meths.add m (Meths.find m table.methods) s with Not_found -> s) + (List.hd table.saved_methods) + meths; + table.saved_methods <- List.tl table.saved_methods end -let set_method table label element = - table.methods <- (label, element) :: table.methods; - put table label element +let get_method_labels table name = + try + Meths.find name table.methods + with Not_found -> + let label = new_anonymous_method () in + table.methods <- Meths.add name [label] table.methods; + [label] + +let get_method_label table name = + List.hd (get_method_labels table name) + +let set_method table name element = + List.iter + (function label -> + table.meth_defs <- (label, element) :: table.meth_defs; + put table label element) + (get_method_labels table name) let get_method table label = let (buck, elem) = decode label in @@ -369,10 +418,14 @@ let new_object table = obj.(0) <- (magic table.buckets : t); obj -let create_class class_info class_init = +let create_class class_info public_methods class_init = let table = new_table () in + List.iter + (function met -> + table.methods <- Meths.add met [new_method met] table.methods) + public_methods; class_init table; - method_count := !method_count + List.length table.methods; + method_count := !method_count + List.length table.meth_defs; if !compact_table then compact_buckets table.buckets; inst_var_count := !inst_var_count + table.size - 1; diff --git a/stdlib/oo.mli b/stdlib/oo.mli index a4ea63c46e..dc52813129 100644 --- a/stdlib/oo.mli +++ b/stdlib/oo.mli @@ -31,13 +31,14 @@ type item type obj_init type class_info val set_initializer: table -> obj_init -> unit -val inheritance: table -> class_info -> string list -> unit +val inheritance: table -> class_info -> string list -> string list -> unit val get_method: table -> label -> item -val set_method: table -> label -> item -> unit +val set_method: table -> string -> item -> unit +val get_method_label: table -> string -> label val get_variable: table -> string -> int val hide_variable: table -> string -> unit val get_private_variable: table -> string -> int -val create_class: class_info -> (table -> unit) -> unit +val create_class: class_info -> string list -> (table -> unit) -> unit (* Objects *) type t diff --git a/testobjects/Exemples.exp b/testobjects/Exemples.exp index 82bd956c10..5d55e083d1 100644 --- a/testobjects/Exemples.exp +++ b/testobjects/Exemples.exp @@ -12,9 +12,9 @@ end # class color_point (int) (string) = val c : string val mutable x : int + method color : string method get_x : int method move : int -> unit - method color : string end # val p' : color_point = <obj> # - : int * string = 5, "red" @@ -41,15 +41,15 @@ end constraint 'a = < move : int -> unit; .. > val mutable center : 'a method center : 'a - method set_center : 'a -> unit method move : int -> unit + method set_center : 'a -> unit end # class 'a circle ('a) = constraint 'a = #point val mutable center : 'a method center : 'a - method set_center : 'a -> unit method move : int -> unit + method set_center : 'a -> unit end # val c : point circle = <obj> val c' : color_point circle = <obj> @@ -57,9 +57,9 @@ val c' : color_point circle = <obj> constraint 'a = #color_point val mutable center : 'a method center : 'a - method set_center : 'a -> unit - method move : int -> unit method color : string + method move : int -> unit + method set_center : 'a -> unit end # Characters 28-29: This expression has type point = < get_x : int; move : int -> unit > @@ -102,9 +102,9 @@ end # class printable_color_point (int) (string) = val c : string val mutable x : int + method color : string method get_x : int method move : int -> unit - method color : string method print : unit end # val p' : printable_color_point = <obj> @@ -120,30 +120,30 @@ end # - : int = 7 # - : (< get_x : int; move : int -> 'a; .. > as 'a) -> functional_point = <fun> # class virtual 'a lst (unit) = - method map : ('a -> 'a) -> 'a lst + virtual hd : 'a method iter : ('a -> unit) -> unit - method print : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst virtual null : bool - virtual hd : 'a + method print : ('a -> unit) -> unit virtual tl : 'a lst end class 'a nil (unit) = - method null : bool method hd : 'a - method tl : 'a lst - method map : ('a -> 'a) -> 'a lst method iter : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst + method null : bool method print : ('a -> unit) -> unit + method tl : 'a lst end class 'a cons ('a) ('a lst) = val h : 'a val t : 'a lst - method null : bool method hd : 'a - method tl : 'a lst - method map : ('a -> 'a) -> 'a lst method iter : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst + method null : bool method print : ('a -> unit) -> unit + method tl : 'a lst end # val l1 : int cons = <obj> # (3::10::[])- : unit = () @@ -160,8 +160,8 @@ end end # class int_comparable2 (int) : 'a = method leq : 'a -> bool - method x : int method set_x : int -> unit + method x : int end # class 'a sorted_list (unit) = constraint 'a = #comparable @@ -190,8 +190,8 @@ is not compatible with type # class int_comparable3 (int) = val mutable x : int method leq : int_comparable -> bool - method x : int method setx : int -> unit + method x : int end # val c3 : int_comparable3 = <obj> # - : unit = () @@ -223,32 +223,32 @@ is not compatible with type # class 'a link ('a) : 'b = val mutable next : 'b option val mutable x : 'a - method x : 'a + method append : 'b option -> unit method next : 'b option - method set_x : 'a -> unit method set_next : 'b option -> unit - method append : 'b option -> unit + method set_x : 'a -> unit + method x : 'a end # class 'a double_link ('a) : 'b = val mutable next : 'b option val mutable prev : 'b option val mutable x : 'a - method x : 'a - method next : 'b option - method set_x : 'a -> unit - method set_next : 'b option -> unit method append : 'b option -> unit + method next : 'b option method prev : 'b option + method set_next : 'b option -> unit method set_prev : 'b option -> unit + method set_x : 'a -> unit + method x : 'a end # val fold_right : ('a -> 'b -> 'b) -> 'a #link option -> 'b -> 'b = <fun> # class calculator (unit) : 'a = val mutable acc : float val mutable arg : float val mutable equals : 'a -> float - method arg : float method acc : float method add : 'a + method arg : float method enter : float -> 'a method equals : float method sub : 'a @@ -260,9 +260,9 @@ end val mutable acc : float val mutable arg : float val mutable equals : 'a -> float - method arg : float method acc : float method add : 'a + method arg : float method enter : float -> 'a method equals : float method sub : 'a @@ -273,26 +273,26 @@ end # class calculator (float) (float) = val acc : float val arg : float - method enter : float -> calculator method add : calculator_add - method sub : calculator_sub + method enter : float -> calculator method equals : float + method sub : calculator_sub end class calculator_add (float) (float) = val acc : float val arg : float - method enter : float -> calculator method add : calculator_add - method sub : calculator_sub + method enter : float -> calculator method equals : float + method sub : calculator_sub end class calculator_sub (float) (float) = val acc : float val arg : float - method enter : float -> calculator method add : calculator_add - method sub : calculator_sub + method enter : float -> calculator method equals : float + method sub : calculator_sub end # val calculator : calculator = <obj> # - : float = 5 diff --git a/testobjects/Tests.exp b/testobjects/Tests.exp index 9dba19fbf5..c28ef5adb3 100644 --- a/testobjects/Tests.exp +++ b/testobjects/Tests.exp @@ -131,13 +131,13 @@ end val x : int val y : int val z : int + method a : int + method b : int + method t : int + method u : int method x : int method y : int method z : int - method t : int - method u : int - method a : int - method b : int end # val e : e = <obj> # - : int * int * int * int * int * int * int = 1, 3, 2, 2, 3, 5, 7 @@ -175,7 +175,7 @@ end end # - : int * int * int * int = 2, 1, 1, 1 # module M : sig class c (unit) = method xc : int end end -# class d (unit) = val x : int method xd : int method xc : int end +# class d (unit) = val x : int method xc : int method xd : int end # - : int * int = 1, 2 # Characters 7-143: The type variable 'a is not bound in implicit type definition @@ -221,4 +221,8 @@ Type bool is not a subtype of type int # type 'a t = < x : 'a > # - : (< x : 'a > as 'a) t -> unit = <fun> # - : (< x : 'a > as 'a) t -> unit = <fun> +# class c (unit) = private method m : int method n : int end +# class d (unit) = private method m : int method n : int method o : int end +# - : int * int = 1, 1 +# class c (unit) = method m : int end # diff --git a/testobjects/Tests.ml b/testobjects/Tests.ml index 0513888141..29051fa70d 100644 --- a/testobjects/Tests.ml +++ b/testobjects/Tests.ml @@ -300,3 +300,17 @@ class 'a c () = constraint 'a = unit -> < .. > method m (f : 'a) = f () end;; + +class c () as self = + private method m = 1 + method n = self#m +end;; + +class d () as self = + inherit c () + method o = self#m +end;; + +let x = new d () in x#n, x#o;; + +class c () = virtual m : int private method m = 1 end;; diff --git a/tools/ocamlprof.ml b/tools/ocamlprof.ml index 7467f645a0..43de3b4cd3 100644 --- a/tools/ocamlprof.ml +++ b/tools/ocamlprof.ml @@ -264,9 +264,9 @@ let rewrite_class_field = Pcf_inher (_, _, l, _, _) -> List.iter rewrite_exp l | Pcf_val (_, _, _, Some sexp, _) -> rewrite_exp sexp | Pcf_val (_, _, _, None, _) | Pcf_virt _ -> () - | Pcf_meth (_, ({pexp_desc = Pexp_function _} as sexp), _) -> + | Pcf_meth (_, _, ({pexp_desc = Pexp_function _} as sexp), _) -> rewrite_exp sexp - | Pcf_meth (_, sexp, _) -> + | Pcf_meth (_, _, sexp, _) -> if !instr_fun then insert_profile sexp.pexp_loc; rewrite_exp sexp diff --git a/toplevel/genprintval.ml b/toplevel/genprintval.ml index e6a4a5065a..167489d459 100644 --- a/toplevel/genprintval.ml +++ b/toplevel/genprintval.ml @@ -328,7 +328,7 @@ module Make(Obj : Obj) = struct end | Tobject (_, _) -> print_string "<obj>" - | Tfield(_, _, _) | Tnil | Tlink _ -> + | Tfield(_, _, _, _) | Tnil | Tlink _ -> fatal_error "Printval.print_value" and print_val_list prio depth obj ty_list = diff --git a/typing/btype.ml b/typing/btype.ml index 957570d9bf..e1bd4c9f7a 100644 --- a/typing/btype.ml +++ b/typing/btype.ml @@ -44,6 +44,10 @@ let rec repr = repr t' | t -> t +let rec field_kind_repr = + function + Fvar {contents = Some kind} -> field_kind_repr kind + | kind -> kind (**********************************) (* Utilities for type traversal *) @@ -59,7 +63,7 @@ let iter_type_expr f ty = | Tobject(ty, {contents = Some (_, p)}) -> f ty; List.iter f p | Tobject (ty, _) -> f ty - | Tfield (_, ty1, ty2) -> f ty1; f ty2 + | Tfield (_, _, ty1, ty2) -> f ty1; f ty2 | Tnil -> () | Tlink ty -> f ty diff --git a/typing/btype.mli b/typing/btype.mli index d19bb3666b..2fcf24f04e 100644 --- a/typing/btype.mli +++ b/typing/btype.mli @@ -27,6 +27,10 @@ val newmarkedgenvar: unit -> type_expr val repr: type_expr -> type_expr (* Return the canonical representative of a type. *) +val field_kind_repr: field_kind -> field_kind + (* Return the canonical representative of an object field + kind. *) + (**** Utilities for type traversal ****) val iter_type_expr: (type_expr -> unit) -> type_expr -> unit diff --git a/typing/includecore.ml b/typing/includecore.ml index 2265dcf8b6..e3f7b75cf7 100644 --- a/typing/includecore.ml +++ b/typing/includecore.ml @@ -86,6 +86,17 @@ let encode_val (mut, ty) rem = end ::ty::rem +let meths meths1 meths2 = + Meths.fold + (fun nam t2 (ml1, ml2) -> + (begin try + Meths.find nam meths1 :: ml1 + with Not_found -> + ml1 + end, + t2 :: ml2)) + meths2 ([], []) + let vars vars1 vars2 = Vars.fold (fun lab v2 (vl1, vl2) -> @@ -102,14 +113,26 @@ let class_types env d1 d2 = Ctype.equal env true (d1.cty_self::d1.cty_params) (d2.cty_self::d2.cty_params) && - (* Same concretes methods *) - Concr.equal d1.cty_concr d2.cty_concr + (* Fewer concretes methods *) + Concr.subset d2.cty_concr d1.cty_concr && (* If virtual, stays virtual *) (d1.cty_new <> None or d2.cty_new = None) && + (* Virtual methods cannot be hidden *) + Meths.fold + (fun lab ty res -> + res && + (Concr.mem lab d1.cty_concr || + try Meths.find lab d2.cty_meths; true with Not_found -> false)) + d1.cty_meths + true + && (* Less general *) + let (m1, m2) = meths d1.cty_meths d2.cty_meths in let (v1, v2) = vars d1.cty_vars d2.cty_vars in - let t1 = Ctype.newgenty (Ttuple (d1.cty_self::v1@d1.cty_args)) in - let t2 = Ctype.newgenty (Ttuple (d2.cty_self::v2@d2.cty_args)) in + let t1 = Ctype.newgenty (Ttuple (d1.cty_self::m1@v1@d1.cty_args)) in + let t2 = Ctype.newgenty (Ttuple (d2.cty_self::m2@v2@d2.cty_args)) in + List.length d1.cty_args = List.length d2.cty_args + && Ctype.moregeneral env true t1 t2 diff --git a/typing/printtyp.ml b/typing/printtyp.ml index 11a002239e..ab1814dceb 100644 --- a/typing/printtyp.ml +++ b/typing/printtyp.ml @@ -126,7 +126,7 @@ let rec mark_loops_rec visited ty = List.iter (mark_loops_rec visited) l end end - | Tfield(_, ty1, ty2) -> + | Tfield(_, kind, ty1, ty2) when field_kind_repr kind = Fpresent -> mark_loops_rec visited ty1; mark_loops_rec visited ty2 | Tnil -> () | Tlink _ -> fatal_error "Printtyp.mark_loops_rec (2)" @@ -220,7 +220,17 @@ and typobject sch ty fi nm = open_box 2; print_string "< "; (let (fields, rest) = flatten_fields fi in - typfields sch rest fields); + let present_fields = + List.fold_right + (fun (n, k, t) l -> + match field_kind_repr k with + Fpresent -> + (n, t)::l + | _ -> + l) + fields [] + in + typfields sch rest present_fields); print_string " >"; close_box () | Some (p, {desc = Tvar}::tyl) -> @@ -400,25 +410,26 @@ let class_var l (m, t) = type_sch t; close_box() -let metho kind (l, t) = +let metho public concrete lab ty = print_space (); open_box 2; - print_string kind; - print_string l; + if not (List.mem_assoc lab public) then print_string "private "; + if Concr.mem lab concrete then print_string "method " + else print_string "virtual "; + print_string lab; print_string " :"; - print_space(); - type_sch t; - close_box() + print_space (); + type_sch ty; + close_box () let methods_of_type ty = match (repr ty).desc with Tobject (m, _) -> m | _ -> fatal_error "Printtyp.methods_of_type" -let rec list_meths ty = - match (repr ty).desc with - Tfield(lab, ty, ty') -> (lab, ty) :: (list_meths ty') - | _ -> [] +let rec list_public_methods ty = + let (fields, _) = flatten_fields ty in + List.map (function (m, _, t) -> (m, t)) fields let class_type id cl_ty = let self = repr cl_ty.cty_self in @@ -437,6 +448,7 @@ let class_type id cl_ty = List.iter mark_loops params; List.iter mark_loops args; Vars.iter (fun _ (_, ty) -> mark_loops ty) vars; + Meths.iter (fun _ ty -> mark_loops ty) cl_ty.cty_meths; List.iter name_of_type params; open_hvbox 2; open_box 0; @@ -458,18 +470,12 @@ let class_type id cl_ty = close_box (); List.iter constrain params; Vars.iter class_var vars; - let meths = list_meths (methods_of_type self) in - let (meths, virt) = - List.fold_right - (fun ((lab, ty) as m) (ml, vl) -> - if Concr.mem lab cl_ty.cty_concr then - (m::ml, vl) - else - (ml, m::vl)) - meths - ([], []) in - List.iter (metho "method ") meths; - List.iter (metho "virtual ") virt; + let public_methods = list_public_methods (methods_of_type self) in + let methods = + List.fold_left (fun m (lab, ty) -> Meths.add lab ty m) + cl_ty.cty_meths public_methods + in + Meths.iter (metho public_methods cl_ty.cty_concr) methods; print_break 1 (-2); print_string "end"; close_box() diff --git a/typing/subst.ml b/typing/subst.ml index 1f39890095..4e199642e3 100644 --- a/typing/subst.ml +++ b/typing/subst.ml @@ -98,8 +98,13 @@ let rec typexp s ty = None -> None | Some (p, tl) -> Some (type_path s p, List.map (typexp s) tl))) - | Tfield(label, t1, t2) -> - Tfield(label, typexp s t1, typexp s t2) + | Tfield(label, kind, t1, t2) -> + begin match field_kind_repr kind with + Fpresent -> + Tfield(label, Fpresent, typexp s t1, typexp s t2) + | _ -> + Tlink(typexp s t2) + end | Tnil -> Tnil end; @@ -158,9 +163,8 @@ let class_type s decl = let decl = { cty_params = List.map (typexp s) decl.cty_params; cty_args = List.map (typexp s) decl.cty_args; - cty_vars = - Vars.fold (fun l (m, t) -> Vars.add l (m, typexp s t)) - decl.cty_vars Vars.empty; + cty_vars = Vars.map (function (m, t) -> (m, typexp s t)) decl.cty_vars; + cty_meths = Meths.map (typexp s) decl.cty_meths; cty_self = typexp s decl.cty_self; cty_concr = decl.cty_concr; cty_new = @@ -173,6 +177,7 @@ let class_type s decl = List.iter unmark_type decl.cty_params; List.iter unmark_type decl.cty_args; Vars.iter (fun l (m, t) -> unmark_type t) decl.cty_vars; + Meths.iter (fun l t -> unmark_type t) decl.cty_meths; unmark_type decl.cty_self; begin match decl.cty_new with None -> () diff --git a/typing/typeclass.ml b/typing/typeclass.ml index fdd2ca6fe1..2d85edeee3 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -68,24 +68,26 @@ let check_mutable loc lab mut mut' = | _ -> () -let rec add_methods env self concr concr_lst t = +let rec add_methods env self t = match (Ctype.repr t).desc with - Tfield (lab, _, t') -> - Ctype.filter_method env lab self; - if Concr.mem lab concr_lst then - (Ctype.filter_method env lab concr; ()); - add_methods env self concr concr_lst t' + Tfield (lab, k, _, t') -> + if Btype.field_kind_repr k = Fpresent then begin + Ctype.filter_method env lab Public self; + end; + add_methods env self t' | _ -> () -(* Make sure taht [self] has at least the methods of [obj]. *) +(* Make sure that [self] has at least the methods of [obj]. *) let equalize_methods env self obj = match (Ctype.expand_head env obj).desc with Tobject (ty, _) -> let rec equalize_methods_rec t = match (Ctype.repr t).desc with - Tfield (lab, _, t') -> - Ctype.filter_method env lab self; + Tfield (lab, k, _, t') -> + if Btype.field_kind_repr k = Fpresent then begin + Ctype.filter_method env lab Public self; () + end; equalize_methods_rec t' | _ -> () @@ -97,12 +99,14 @@ let equalize_methods env self obj = let rec type_meth env loc self ty = match (Ctype.repr ty).desc with - Tfield (lab, ty, ty') -> - let ty0 = Ctype.filter_method env lab self in - begin try - Ctype.unify env ty ty0 - with Ctype.Unify trace -> - raise(Error(loc, Method_type_mismatch (lab, trace))) + Tfield (lab, k, ty, ty') -> + if Btype.field_kind_repr k = Fpresent then begin + let ty0 = Ctype.filter_method env lab Public self in + begin try + Ctype.unify env ty ty0 + with Ctype.Unify trace -> + raise(Error(loc, Method_type_mismatch (lab, trace))) + end end; type_meth env loc self ty' | _ -> @@ -126,10 +130,12 @@ let insert_value env lab priv mut ty loc vals = let rec closed_scheme t = match (Ctype.repr t).desc with - Tfield (lab, _, t') -> - Ctype.newty (Tfield (lab, Ctype.newvar (), closed_scheme t')) + Tfield (lab, k, _, t') when Btype.field_kind_repr k = Fpresent -> + Ctype.newty (Tfield (lab, Fpresent, Ctype.newvar (), closed_scheme t')) + | Tfield (lab, _, _, t') -> + closed_scheme t' | Tnil -> - Ctype.newty Tnil + Ctype.newty Tnil | _ -> fatal_error "Typeclass.closed_scheme" @@ -147,9 +153,11 @@ let change_value_status lab priv mut loc vals = let missing_method env ty ty' = let rec missing_method_rec met= match (Ctype.repr met).desc with - Tfield(lab, _, met') -> + Tfield(lab, k, _, met') -> begin try - Ctype.filter_method env lab ty; + if Btype.field_kind_repr k = Fpresent then begin + Ctype.filter_method env lab Public ty; () + end; missing_method_rec met' with Ctype.Unify _ -> lab @@ -167,6 +175,7 @@ let generalize_class cl_sig = List.iter Ctype.generalize cl_sig.cty_params; List.iter Ctype.generalize cl_sig.cty_args; Vars.iter (fun l (m, t) -> Ctype.generalize t) cl_sig.cty_vars; + Meths.iter (fun l t -> Ctype.generalize t) cl_sig.cty_meths; Ctype.generalize cl_sig.cty_self; match cl_sig.cty_new with Some ty -> Ctype.generalize ty | None -> () @@ -181,7 +190,6 @@ let make_stub env (cl, obj_id, cl_id) = (* Create self (class type) *) let self = Ctype.newobj (Ctype.newvar ()) in - let concr = Ctype.newobj (Ctype.newvar ()) in (* Find concrete methods and marks methods *) let concr_meths = @@ -197,26 +205,23 @@ let make_stub env (cl, obj_id, cl_id) = in begin match (Ctype.expand_head env anc.cty_self).desc with Tobject (ty, _) -> - add_methods env self concr anc.cty_concr ty; + add_methods env self ty; Concr.union anc.cty_concr meths | _ -> fatal_error "Typeclass.make_stub" end | Pcf_val _ -> meths - | Pcf_virt (lab, _, _) -> - Ctype.filter_method env lab self; + | Pcf_virt (lab, priv, _, _) -> + Ctype.filter_method env lab priv self; meths - | Pcf_meth (lab, _, _) -> - Ctype.filter_method env lab self; - Ctype.filter_method env lab concr; + | Pcf_meth (lab, priv, _, _) -> + Ctype.filter_method env lab priv self; Concr.add lab meths) Concr.empty cl.pcl_field in - Ctype.close_object concr; Ctype.end_def (); Ctype.generalize self; - Ctype.generalize concr; (* Temporary object type *) let temp_obj_params = @@ -267,15 +272,17 @@ let make_stub env (cl, obj_id, cl_id) = in let cl_temp_sig = { cty_params = []; cty_args = []; cty_vars = Vars.empty; + cty_meths = Meths.empty; cty_self = self; cty_concr = concr_meths; cty_new = new_ty } in let (id, temp_env) = Env.enter_class cl.pcl_name cl_temp_sig temp_env in - ((cl, id, cl_id, obj_id, self, concr, concr_meths, new_args, new_ty, + ((cl, id, cl_id, obj_id, self, concr_meths, new_args, new_ty, temp_cl, temp_cl_params, cl_abbrev, temp_obj, temp_obj_params, abbrev), temp_env) -let type_class_field env var_env self cl (met_env, fields, vars_sig) = +let type_class_field env var_env self cl + (met_env, fields, vars_sig, meths) = function Pcf_inher (cl_name, params, args, super, loc) -> (* Find class type *) @@ -285,7 +292,9 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = with Not_found -> raise(Error(loc, Unbound_class cl_name)) in - let (params', args', vars', self') = Ctype.instance_class cl_type in + let (params', args', vars', meths', self') = + Ctype.instance_class cl_type + in (* Unify parameters *) if List.length params <> List.length params' then @@ -318,21 +327,35 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = vars' ([], vars_sig, met_env) in + (* Methods *) + let meths = + Meths.fold + (fun lab ty m -> + let (id, ty') = + try Meths.find lab m with Not_found -> + (Ident.create lab, + Ctype.filter_method var_env lab Private self) + in + begin try Ctype.unify env ty ty' with Ctype.Unify trace -> + raise(Error(loc, Method_type_mismatch (lab, trace))) + end; + Meths.add lab (id, ty) m) + meths' meths + in + (* Self type *) let ty' = Ctype.expand_head var_env self' in begin match ty'.desc with Tobject (fi, _) -> - if ty' != Ctype.expand_head var_env self then begin - if not (Ctype.opened_object self') then - begin try - Ctype.unify var_env self (Ctype.newobj (closed_scheme fi)) - with Ctype.Unify _ -> - let lab = missing_method var_env self' self in - raise(Error(loc, Closed_ancestor (cl.pcl_name, path, lab))) - end; - ty'.desc <- Tlink self; - type_meth var_env loc self fi - end + if not (Ctype.opened_object self') then + begin try + Ctype.unify var_env self (Ctype.newobj (closed_scheme fi)) + with Ctype.Unify _ -> + let lab = missing_method var_env self' self in + raise(Error(loc, Closed_ancestor (cl.pcl_name, path, lab))) + end; + Ctype.unify var_env ty' self; + type_meth var_env loc self fi | _ -> fatal_error "Typeclass.transl_class" end; @@ -347,8 +370,9 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = let used_methods = Concr.fold (fun lab rem -> - Ctype.unify met_env (Ctype.filter_method met_env lab ty) - (Ctype.filter_method met_env lab self); + Ctype.unify met_env + (Ctype.filter_method met_env lab Public ty) + (Ctype.filter_method met_env lab Public self); (lab, Ident.create lab)::rem) cl_type.cty_concr [] @@ -360,7 +384,9 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = in (used_methods, met_env) in - (met_env, Cf_inher (path, args, vars, met)::fields, vars_sig) + let met' = Meths.fold (fun lab _ rem -> lab::rem) cl_type.cty_meths [] in + (met_env, Cf_inher (path, args, vars, met, met')::fields, + vars_sig, meths) | Pcf_val (lab, priv, mut, sinit, loc) -> begin match sinit with @@ -371,7 +397,8 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = {val_type = exp.exp_type; val_kind = Val_ivar mut} met_env in (met_env, Cf_val (lab, id, priv, Some exp)::fields, - insert_value var_env lab priv mut exp.exp_type loc vars_sig) + insert_value var_env lab priv mut exp.exp_type loc vars_sig, + meths) | None -> let (vars_sig, ty) = change_value_status lab priv mut loc vars_sig @@ -380,24 +407,31 @@ let type_class_field env var_env self cl (met_env, fields, vars_sig) = Env.enter_value lab {val_type = ty; val_kind = Val_ivar mut} met_env in - (met_env, Cf_val (lab, id, priv, None)::fields, vars_sig) + (met_env, Cf_val (lab, id, priv, None)::fields, vars_sig, meths) end - | Pcf_virt (lab, ty, loc) -> + | Pcf_virt (lab, priv, ty, loc) -> let ty = transl_simple_type met_env false ty in - let ty' = Ctype.filter_method var_env lab self in - begin try Ctype.unify var_env ty ty' with Ctype.Unify trace -> + let ty'' = Ctype.filter_method var_env lab priv self in + let (id, ty') = + try Meths.find lab meths with Not_found -> (Ident.create lab, ty'') + in + begin try Ctype.unify var_env ty ty'' with Ctype.Unify trace -> raise(Error(loc, Method_type_mismatch (lab, trace))) end; - (met_env, fields, vars_sig) + (met_env, fields, vars_sig, Meths.add lab (id, ty) meths) + + | Pcf_meth (lab, priv, expr, loc) -> + let ty' = Ctype.filter_method var_env lab priv self in + let (id, ty) = + try Meths.find lab meths with Not_found -> (Ident.create lab, ty') + in + let meths = Meths.add lab (id, ty) meths in + let (texp, meths) = type_method met_env self cl.pcl_self meths expr ty in + (met_env, Cf_meth (lab, texp)::fields, vars_sig, meths) - | Pcf_meth (lab, expr, loc) -> - let ty = Ctype.filter_method var_env lab self in - let texp = type_method met_env self cl.pcl_self expr ty in - (met_env, Cf_meth (lab, texp)::fields, vars_sig) - let transl_class temp_env env - (cl, id, cl_id, obj_id, self, concr, concr_meths, new_args, new_ty, + (cl, id, cl_id, obj_id, self, concr_meths, new_args, new_ty, temp_cl, temp_cl_params, cl_abbrev, temp_obj, temp_obj_params, abbrev) = reset_type_variables (); @@ -437,9 +471,9 @@ let transl_class temp_env env (* Type arguments and fields *) let (args, var_env) = type_pattern_list temp_env cl.pcl_args in let arg_sig = List.map (fun exp -> exp.pat_type) args in - let (_, fields, vars_sig) = + let (_, fields, vars_sig, meths) = List.fold_left (type_class_field env var_env self cl) - (temp_env, [], Vars.empty) + (temp_env, [], Vars.empty, Meths.empty) cl.pcl_field in @@ -452,6 +486,7 @@ let transl_class temp_env env List.iter Ctype.generalize params; List.iter Ctype.generalize arg_sig; Vars.iter (fun l (m, t) -> Ctype.generalize t) vars_sig; + Meths.iter (fun l (i, t) -> Ctype.generalize t) meths; Ctype.generalize self; (* Temporary class abbreviation *) @@ -498,53 +533,73 @@ let transl_class temp_env env let cl_imp = { cl_args = args; cl_field = List.rev fields; + cl_pub_meths = []; + cl_meths = Meths.map (function (id, ty) -> id) meths; cl_loc = cl.pcl_loc } in let cl_sig = { cty_params = params; cty_args = arg_sig; cty_vars = vars_sig; + cty_meths = Meths.map (function (id, ty) -> ty) meths; cty_self = self; cty_concr = concr_meths; cty_new = new_ty } in let new_env = Env.add_class id cl_sig env in - ((cl, id, cl_id, obj_id, cl_sig, cl_imp, concr, temp_obj, + ((cl, id, cl_id, obj_id, cl_sig, cl_imp, temp_obj, temp_obj_params), new_env) let build_new_type temp_env env - (cl, id, cl_id, obj_id, cl_sig, cl_imp, concr, temp_obj, + (cl, id, cl_id, obj_id, cl_sig, cl_imp, temp_obj, temp_obj_params) = (* Modify constrainsts to ensure the object abbreviation is well-formed *) - let (params, args, vars, self) = Ctype.instance_class cl_sig in + let (params, args, vars, meths, self) = Ctype.instance_class cl_sig in List.iter2 (Ctype.unify temp_env) params temp_obj_params; (* Never fails *) + (* Hide private methods *) + Ctype.hide_private_methods cl_sig.cty_self; + (* Closeness of self (2) *) if (cl.pcl_closed <> Closed) & not (Ctype.opened_object self) then raise(Error(cl.pcl_loc, Closed_class cl.pcl_name)); - (* Check whether the class can be concrete *) - if cl.pcl_kind = Concrete then begin - let concr = Ctype.instance concr in - try - Ctype.unify temp_env concr temp_obj - with Ctype.Unify _ -> - let lab = missing_method temp_env concr temp_obj in - raise(Error(cl.pcl_loc, Virtual_class (cl.pcl_name, lab))) - end; - equalize_methods temp_env self temp_obj; (* self should not be an abbreviation (printtyp) *) let exp_self = Ctype.expand_head temp_env self in - (* Final class type *) + let public_methods = + match (Ctype.repr exp_self).desc with + Tobject (fi, _) -> + let (meths, _) = Ctype.flatten_fields fi in + List.map (function (lab, _, _) -> lab) meths + | _ -> fatal_error "Typeclass.build_new_type" + in + + (* Check whether the class can be concrete *) + if cl.pcl_kind = Concrete then + List.iter + (function m -> + if not (Concr.mem m cl_sig.cty_concr) then + raise(Error(cl.pcl_loc, Virtual_class (cl.pcl_name, m)))) + public_methods; + + (* Final class implementation and interface *) + let cl_imp = + { cl_args = cl_imp.cl_args; + cl_field = cl_imp.cl_field; + cl_pub_meths = public_methods; + cl_meths = cl_imp.cl_meths; + cl_loc = cl_imp.cl_loc } + in let cl_sig = { cty_params = params; cty_args = args; cty_vars = vars; + cty_meths = meths; cty_self = exp_self; cty_concr = cl_sig.cty_concr; cty_new = cl_sig.cty_new } (* new is still monomorphic *) @@ -630,7 +685,6 @@ let make_stub env (cl, obj_id, cl_id) = (* Create self (class type) *) let self = Ctype.newobj (Ctype.newvar ()) in - let concr = Ctype.newobj (Ctype.newvar ()) in (* Find concrete methods and marks methods *) let concr_meths = @@ -646,26 +700,23 @@ let make_stub env (cl, obj_id, cl_id) = in begin match (Ctype.expand_head env anc.cty_self).desc with Tobject (ty, _) -> - add_methods env self concr anc.cty_concr ty; + add_methods env self ty; Concr.union anc.cty_concr meths | _ -> fatal_error "Typeclass.make_stub (type)" end | Pctf_val _ -> meths - | Pctf_virt (lab, _, _) -> - Ctype.filter_method env lab self; + | Pctf_virt (lab, priv, _, _) -> + Ctype.filter_method env lab priv self; meths - | Pctf_meth (lab, _, _) -> - Ctype.filter_method env lab self; - Ctype.filter_method env lab concr; + | Pctf_meth (lab, priv, _, _) -> + Ctype.filter_method env lab priv self; Concr.add lab meths) Concr.empty cl.pcty_field in - Ctype.close_object concr; Ctype.end_def (); Ctype.generalize self; - Ctype.generalize concr; (* Temporary object type *) let temp_obj_params = @@ -708,17 +759,17 @@ let make_stub env (cl, obj_id, cl_id) = (* Temporary class type *) let cl_temp_sig = { cty_params = []; - cty_args = []; cty_vars = Vars.empty; + cty_args = []; cty_vars = Vars.empty; cty_meths = Meths.empty; cty_self = self; cty_concr = concr_meths; cty_new = None } in let (id, temp_env) = Env.enter_class cl.pcty_name cl_temp_sig temp_env in - ((cl, id, cl_id, obj_id, self, concr, concr_meths, temp_cl, + ((cl, id, cl_id, obj_id, self, concr_meths, temp_cl, temp_cl_params, cl_abbrev, temp_obj, temp_obj_params, abbrev), temp_env) -let type_class_field env var_env self cl vars_sig = +let type_class_field env var_env self cl (vars_sig, meths_sig) = function Pctf_inher (cl_name, params, loc) -> (* Find class type *) @@ -728,7 +779,7 @@ let type_class_field env var_env self cl vars_sig = with Not_found -> raise (Error (loc, Unbound_class cl_name)) in - let (params', _, vars', self') = Ctype.instance_class cl_type in + let (params', _, vars', meths', self') = Ctype.instance_class cl_type in (* Unify parameters *) if List.length params <> List.length params' then @@ -748,56 +799,70 @@ let type_class_field env var_env self cl vars_sig = vars' vars_sig in + let meths_sig = + Meths.fold + (fun lab ty m_sig -> + let ty' = + try Meths.find lab m_sig with Not_found -> + Ctype.filter_method var_env lab Private self + in + begin try Ctype.unify env ty ty' with Ctype.Unify trace -> + raise(Error(loc, Method_type_mismatch (lab, trace))) + end; + Meths.add lab ty m_sig) + meths' meths_sig + in + (* Self type *) let ty' = Ctype.expand_head var_env self' in begin match ty'.desc with - Tobject (fi, _) -> - if not (Ctype.opened_object self') then - begin try - Ctype.unify var_env self (Ctype.newobj (closed_scheme fi)) - with Ctype.Unify _ -> - let lab = missing_method var_env self' self in - raise(Error(loc, Closed_ancestor (cl.pcty_name, path, lab))) - end; - ty'.desc <- Tlink self; - type_meth var_env loc self fi - | _ -> - fatal_error "Typeclass.type_class_field (type)" + Tobject (fi, _) -> + if ty' != Ctype.expand_head var_env self then begin + if not (Ctype.opened_object self') then + begin try + Ctype.unify var_env self (Ctype.newobj (closed_scheme fi)) + with Ctype.Unify _ -> + let lab = missing_method var_env self' self in + raise(Error(loc, Closed_ancestor (cl.pcty_name, path, lab))) + end; + Ctype.unify var_env ty' self; + type_meth var_env loc self fi + end + | _ -> + fatal_error "Typeclass.type_class_field (type)" end; - vars_sig + (vars_sig, meths_sig) | Pctf_val (lab, priv, mut, sty, loc) -> begin match sty with Some sty -> let ty = transl_simple_type var_env false sty in - insert_value var_env lab priv mut ty loc vars_sig + (insert_value var_env lab priv mut ty loc vars_sig, meths_sig) | None -> - fst (change_value_status lab priv mut loc vars_sig) + (fst (change_value_status lab priv mut loc vars_sig), meths_sig) end - | Pctf_virt (lab, sty, loc) -> + | Pctf_virt (lab, priv, sty, loc) -> let ty = transl_simple_type var_env false sty in - let ty' = Ctype.filter_method var_env lab self in + let ty'' = Ctype.filter_method var_env lab priv self in + let ty' = try Meths.find lab meths_sig with Not_found -> ty'' in begin try Ctype.unify var_env ty ty' with Ctype.Unify trace -> raise(Error(loc, Method_type_mismatch (lab, trace))) end; - vars_sig + (vars_sig, Meths.add lab ty meths_sig) - | Pctf_meth (lab, Some sty, loc) -> + | Pctf_meth (lab, priv, sty, loc) -> let ty = transl_simple_type var_env false sty in - let ty' = Ctype.filter_method var_env lab self in + let ty'' = Ctype.filter_method var_env lab priv self in + let ty' = try Meths.find lab meths_sig with Not_found -> ty'' in begin try Ctype.unify var_env ty ty' with Ctype.Unify trace -> raise(Error(loc, Method_type_mismatch (lab, trace))) end; - vars_sig - - | Pctf_meth (lab, None, loc) -> - Ctype.filter_method var_env lab self; - vars_sig + (vars_sig, Meths.add lab ty meths_sig) let transl_class temp_env env - (cl, id, cl_id, obj_id, self, concr, concr_meths, temp_cl, + (cl, id, cl_id, obj_id, self, concr_meths, temp_cl, temp_cl_params, cl_abbrev, temp_obj, temp_obj_params, abbrev) = reset_type_variables (); @@ -838,9 +903,9 @@ let transl_class temp_env env let arg_sig = List.map (transl_simple_type temp_env false) cl.pcty_args in (* Translate fields *) - let vars_sig = + let (vars_sig, meths_sig) = List.fold_left (type_class_field env temp_env self cl) - Vars.empty cl.pcty_field + (Vars.empty, Meths.empty) cl.pcty_field in (* Closeness of self *) @@ -852,6 +917,7 @@ let transl_class temp_env env List.iter Ctype.generalize params; List.iter Ctype.generalize arg_sig; Vars.iter (fun l (m, t) -> Ctype.generalize t) vars_sig; + Meths.iter (fun l t -> Ctype.generalize t) meths_sig; Ctype.generalize self; (* Temporary class abbreviation *) @@ -891,39 +957,33 @@ let transl_class temp_env env { cty_params = params; cty_args = arg_sig; cty_vars = vars_sig; + cty_meths = meths_sig; cty_self = self; cty_concr = concr_meths; cty_new = None } in let new_env = Env.add_class id cl_sig env in - ((cl, id, cl_id, obj_id, cl_sig, concr, abbrev, temp_obj, + ((cl, id, cl_id, obj_id, cl_sig, abbrev, temp_obj, temp_obj_params), new_env) let build_new_type temp_env env - (cl, id, cl_id, obj_id, cl_sig, concr, abbrev, temp_obj, + (cl, id, cl_id, obj_id, cl_sig, abbrev, temp_obj, temp_obj_params) = (* Modify constrainsts to ensure the object abbreviation is well-formed *) - let (params, args, vars, self) = Ctype.instance_class cl_sig in + let (params, args, vars, meths, self) = Ctype.instance_class cl_sig in List.iter2 (Ctype.unify temp_env) params temp_obj_params; (* Never fails *) + (* Hide private methods *) + Ctype.hide_private_methods cl_sig.cty_self; + (* Closeness of self (2) *) if (cl.pcty_closed <> Closed) & not (Ctype.opened_object self) then raise(Error(cl.pcty_loc, Closed_class cl.pcty_name)); - (* Check whether the class can be concrete *) - if cl.pcty_kind = Concrete then begin - let concr = Ctype.instance concr in - try - Ctype.unify temp_env concr temp_obj - with Ctype.Unify _ -> - let lab = missing_method temp_env concr temp_obj in - raise(Error(cl.pcty_loc, Virtual_class (cl.pcty_name, lab))) - end; - equalize_methods temp_env self temp_obj; (* self should not be an abbreviation (printtyp) *) @@ -938,11 +998,28 @@ let build_new_type temp_env env None in + let public_methods = + match (Ctype.repr exp_self).desc with + Tobject (fi, _) -> + let (meths, _) = Ctype.flatten_fields fi in + List.map (function (lab, _, _) -> lab) meths + | _ -> fatal_error "Typeclass.build_new_type" + in + + (* Check whether the class can be concrete *) + if cl.pcty_kind = Concrete then + List.iter + (function m -> + if not (Concr.mem m cl_sig.cty_concr) then + raise(Error(cl.pcty_loc, Virtual_class (cl.pcty_name, m)))) + public_methods; + (* Final class type *) let cl_sig = { cty_params = params; cty_args = args; cty_vars = vars; + cty_meths = meths; cty_self = exp_self; cty_concr = cl_sig.cty_concr; cty_new = new_ty } diff --git a/typing/typecore.ml b/typing/typecore.ml index 556a9c893a..0ce889fa4f 100644 --- a/typing/typecore.ml +++ b/typing/typecore.ml @@ -541,37 +541,49 @@ let rec type_exp env sexp = | Pexp_send (e, met) -> let object = type_exp env e in begin try - let typ = filter_method env met object.exp_type in - let exp = - match object.exp_desc with - Texp_ident(path, {val_kind = Val_anc methods}) -> - let (path, desc) = + let (exp, typ) = + match object.exp_desc with + Texp_ident(path, {val_kind = Val_self meths}) -> + begin try (* Private method *) + let (id, typ) = Meths.find met !meths in + (Texp_send(object, Tmeth_val id), typ) + with Not_found -> (* Implicitely defined method *) + let id = Ident.create met in + let typ = filter_method env met Private object.exp_type in + meths := Meths.add met (id, typ) !meths; + (Texp_send(object, Tmeth_val id), typ) + end + | Texp_ident(path, {val_kind = Val_anc methods}) -> + let typ = filter_method env met Public object.exp_type in + let (path, desc) = Env.lookup_value (Longident.Lident "*self*") env in let method_id = List.assoc met methods in - let method_type = newvar () in - let (obj_ty, res_ty) = filter_arrow env method_type in - unify env obj_ty desc.val_type; - unify env res_ty typ; - Texp_apply({exp_desc = Texp_ident(Path.Pident method_id, - {val_type = method_type; - val_kind = Val_reg}); - exp_loc = sexp.pexp_loc; - exp_type = method_type; - exp_env = env }, - [{exp_desc = Texp_ident(path, desc); - exp_loc = object.exp_loc; - exp_type = desc.val_type; - exp_env = env }]) + let method_type = newvar () in + let (obj_ty, res_ty) = filter_arrow env method_type in + unify env obj_ty desc.val_type; + unify env res_ty typ; + (Texp_apply({exp_desc = Texp_ident(Path.Pident method_id, + {val_type = method_type; + val_kind = Val_reg}); + exp_loc = sexp.pexp_loc; + exp_type = method_type; + exp_env = env }, + [{exp_desc = Texp_ident(path, desc); + exp_loc = object.exp_loc; + exp_type = desc.val_type; + exp_env = env }]), + typ) | _ -> - Texp_send(object, met) + (Texp_send(object, Tmeth_name met), + filter_method env met Public object.exp_type) in { exp_desc = exp; exp_loc = sexp.pexp_loc; exp_type = typ; exp_env = env } with Unify _ -> - raise(Error(e.pexp_loc, Undefined_method_err met)) + raise(Error(e.pexp_loc, Undefined_method_err met)) end | Pexp_new cl -> let (cl_path, cl_typ) = @@ -776,7 +788,8 @@ let rec type_expect_fun env sexp ty_expected = | _ -> type_expect env sexp ty_expected -let type_method env self self_name sexp ty_expected = +let type_method env self self_name meths sexp ty_expected = + let meths = ref meths in let (obj, env) = Env.enter_value "*self*" {val_type = self; val_kind = Val_reg} env in @@ -791,7 +804,7 @@ let type_method env self self_name sexp ty_expected = (pattern, env) | Some name -> let (self_name, env) = - Env.enter_value name {val_type = self; val_kind = Val_reg} env + Env.enter_value name {val_type = self; val_kind = Val_self meths} env in ({ pat_desc = Tpat_alias (pattern, self_name); pat_loc = Location.none; @@ -802,7 +815,8 @@ let type_method env self self_name sexp ty_expected = { exp_desc = Texp_function [(pattern, exp)]; exp_loc = sexp.pexp_loc; exp_type = newty (Tarrow(pattern.pat_type, exp.exp_type)); - exp_env = env } + exp_env = env }, + !meths (* Error report *) diff --git a/typing/typecore.mli b/typing/typecore.mli index 3dddcbbccb..d3d210860d 100644 --- a/typing/typecore.mli +++ b/typing/typecore.mli @@ -24,7 +24,9 @@ val type_expression: Env.t -> Parsetree.expression -> Typedtree.expression val type_method: Env.t -> type_expr -> string option -> - Parsetree.expression -> type_expr -> Typedtree.expression + (Ident.t * Types.type_expr) Meths.t -> + Parsetree.expression -> type_expr -> + Typedtree.expression * (Ident.t * Types.type_expr) Meths.t val type_pattern_list: Env.t -> Parsetree.pattern list -> Typedtree.pattern list * Env.t val type_expect: diff --git a/typing/typedtree.ml b/typing/typedtree.ml index d1734d28e7..a5d09e6cac 100644 --- a/typing/typedtree.ml +++ b/typing/typedtree.ml @@ -60,24 +60,30 @@ and expression_desc = | Texp_for of Ident.t * expression * expression * direction_flag * expression | Texp_when of expression * expression - | Texp_send of expression * string + | Texp_send of expression * meth | Texp_new of Path.t | Texp_instvar of Path.t * Path.t | Texp_setinstvar of Path.t * Path.t * expression | Texp_override of Path.t * (Path.t * expression) list +and meth = + Tmeth_name of string + | Tmeth_val of Ident.t + (* Value expressions for classes *) type class_field = Cf_inher of Path.t * expression list * (string * Ident.t) list * - (string * Ident.t) list + (string * Ident.t) list * string list | Cf_val of string * Ident.t * private_flag * expression option | Cf_meth of string * expression type class_def = { cl_args: pattern list; cl_field: class_field list; + cl_pub_meths: string list; + cl_meths: Ident.t Meths.t; cl_loc: Location.t } (* Value expressions for the module language *) diff --git a/typing/typedtree.mli b/typing/typedtree.mli index 403696103f..7e57dc9575 100644 --- a/typing/typedtree.mli +++ b/typing/typedtree.mli @@ -59,24 +59,30 @@ and expression_desc = | Texp_for of Ident.t * expression * expression * direction_flag * expression | Texp_when of expression * expression - | Texp_send of expression * string + | Texp_send of expression * meth | Texp_new of Path.t | Texp_instvar of Path.t * Path.t | Texp_setinstvar of Path.t * Path.t * expression | Texp_override of Path.t * (Path.t * expression) list +and meth = + Tmeth_name of string + | Tmeth_val of Ident.t + (* Value expressions for classes *) type class_field = Cf_inher of Path.t * expression list * (string * Ident.t) list * - (string * Ident.t) list + (string * Ident.t) list * string list | Cf_val of string * Ident.t * private_flag * expression option | Cf_meth of string * expression type class_def = { cl_args: pattern list; cl_field: class_field list; + cl_pub_meths: string list; + cl_meths: Ident.t Meths.t; cl_loc: Location.t } (* Value expressions for the module language *) diff --git a/typing/types.ml b/typing/types.ml index 84808ffe51..b742ef6272 100644 --- a/typing/types.ml +++ b/typing/types.ml @@ -28,7 +28,7 @@ and type_desc = | Ttuple of type_expr list | Tconstr of Path.t * type_expr list * abbrev_memo ref | Tobject of type_expr * (Path.t * type_expr list) option ref - | Tfield of string * type_expr * type_expr + | Tfield of string * field_kind * type_expr * type_expr | Tnil | Tlink of type_expr @@ -37,6 +37,16 @@ and abbrev_memo = | Mcons of Path.t * type_expr * abbrev_memo | Mlink of abbrev_memo ref +and field_kind = + Fvar of field_kind option ref + | Fpresent + | Fabsent + +(* A set of methods, with their types *) + +module OrderedString = struct type t = string let compare = compare end +module Meths = Map.Make(OrderedString) + (* Value descriptions *) type value_description = @@ -47,6 +57,8 @@ and value_kind = Val_reg (* Regular value *) | Val_prim of Primitive.description (* Primitive *) | Val_ivar of mutable_flag (* Instance variable (mutable ?) *) + | Val_self of (Ident.t * type_expr) Meths.t ref + (* Self *) | Val_anc of (string * Ident.t) list (* Ancestor *) (* Constructor descriptions *) @@ -80,7 +92,6 @@ and record_representation = (* Type expressions for classes *) -module OrderedString = struct type t = string let compare = compare end module Vars = Map.Make(OrderedString) module Concr = Set.Make(OrderedString) @@ -88,6 +99,7 @@ type class_type = { cty_params: type_expr list; cty_args: type_expr list; cty_vars: (Asttypes.mutable_flag * type_expr) Vars.t; + cty_meths: type_expr Meths.t; cty_self: type_expr; cty_concr: Concr.t; mutable cty_new: type_expr option } diff --git a/typing/types.mli b/typing/types.mli index a2abd320fb..292966e299 100644 --- a/typing/types.mli +++ b/typing/types.mli @@ -27,7 +27,7 @@ and type_desc = | Ttuple of type_expr list | Tconstr of Path.t * type_expr list * abbrev_memo ref | Tobject of type_expr * (Path.t * type_expr list) option ref - | Tfield of string * type_expr * type_expr + | Tfield of string * field_kind * type_expr * type_expr | Tnil | Tlink of type_expr @@ -36,6 +36,15 @@ and abbrev_memo = | Mcons of Path.t * type_expr * abbrev_memo | Mlink of abbrev_memo ref +and field_kind = + Fvar of field_kind option ref + | Fpresent + | Fabsent + +(* A set of methods, with their types *) + +module Meths : Map.S with type key = string + (* Value descriptions *) type value_description = @@ -46,6 +55,8 @@ and value_kind = Val_reg (* Regular value *) | Val_prim of Primitive.description (* Primitive *) | Val_ivar of mutable_flag (* Instance variable (mutable ?) *) + | Val_self of (Ident.t * type_expr) Meths.t ref + (* Self *) | Val_anc of (string * Ident.t) list (* Ancestor *) (* Constructor descriptions *) @@ -79,13 +90,14 @@ and record_representation = (* Type expressions for classes *) -module Vars : Map.S with type key = string +module Vars : Map.S with type key = string module Concr : Set.S with type elt = string type class_type = { cty_params: type_expr list; cty_args: type_expr list; cty_vars: (mutable_flag * type_expr) Vars.t; + cty_meths: type_expr Meths.t; cty_self: type_expr; cty_concr: Concr.t; mutable cty_new: type_expr option } diff --git a/typing/typetexp.ml b/typing/typetexp.ml index aa9e4d1680..70a59e76b8 100644 --- a/typing/typetexp.ml +++ b/typing/typetexp.ml @@ -181,7 +181,7 @@ and transl_fields env policy = | {pfield_desc = Pfield(s, e)}::l -> let ty1 = transl_type env policy e in let ty2 = transl_fields env policy l in - newty (Tfield (s, ty1, ty2)) + newty (Tfield (s, Fpresent, ty1, ty2)) let transl_simple_type env fixed styp = aliases := Tbl.empty; |
