diff --git a/compiler/src/language_server/inlayhint.re b/compiler/src/language_server/inlayhint.re index b88cdf262..0536aaff1 100644 --- a/compiler/src/language_server/inlayhint.re +++ b/compiler/src/language_server/inlayhint.re @@ -33,6 +33,29 @@ let send_no_result = (~id: Protocol.message_id) => { Protocol.response(~id, `Null); }; +let build_hint = + (position: Protocol.position, message: string): ResponseResult.inlay_hint => { + {label: ": " ++ message, position}; +}; + +let rec resolve_typ = (typ: Types.type_expr) => { + switch (typ.desc) { + | TTyLink(type_expr) + | TTySubst(type_expr) => resolve_typ(type_expr) + | _ => typ + }; +}; +let string_of_typ = (typ: Types.type_expr) => { + Printtyp.string_of_type_scheme(resolve_typ(typ)); +}; + +let is_func_typ = (typ: Types.type_expr) => { + switch (resolve_typ(typ).desc) { + | TTyArrow(_, _, _) => true + | _ => false + }; +}; + let find_hints = program => { let hints = ref([]); open Typedtree; @@ -40,7 +63,70 @@ let find_hints = program => { module Iterator = TypedtreeIter.MakeIterator({ include TypedtreeIter.DefaultIteratorArgument; - // Inlay hints for various expressions can be included here. + + let enter_expression = ({exp_desc, exp_type}: expression) => + switch (exp_desc) { + | TExpLambda(bindings, _) => + List.iter( + ({mb_pat, mb_loc}: match_branch) => { + switch (mb_pat.pat_desc) { + | TPatTuple(args) => + switch (resolve_typ(exp_type).desc) { + | TTyArrow(typ_args, _, _) => + let argument_typs = + List.map( + ((arg, typ: Types.type_expr)) => + switch (arg) { + | Default(_) => None + | _ => Some(typ) + }, + typ_args, + ); + if (List.length(argument_typs) == List.length(args)) { + List.iter( + ((arg: pattern, typ: option(Types.type_expr))) => { + switch (arg.pat_desc, typ) { + | (TPatVar(_, _), Some(typ)) => + let bind_end = arg.pat_loc.loc_end; + let p: Protocol.position = { + line: bind_end.pos_lnum - 1, + character: bind_end.pos_cnum - bind_end.pos_bol, + }; + let typeSignature = string_of_typ(typ); + hints := [build_hint(p, typeSignature), ...hints^]; + | _ => () + } + }, + List.combine(args, argument_typs), + ); + }; + | _ => () + } + | _ => () + } + }, + bindings, + ) + | _ => () + }; + + let enter_binding = ({vb_pat, vb_expr}: value_binding, toplevel: bool) => + if (!toplevel) { + switch (vb_pat) { + | {pat_extra: [], pat_desc: TPatVar(_, {loc})} => + let bind_end = loc.loc_end; + let p: Protocol.position = { + line: bind_end.pos_lnum - 1, + character: bind_end.pos_cnum - bind_end.pos_bol, + }; + let typ = vb_pat.pat_type; + if (!is_func_typ(typ)) { + let typeSignature = string_of_typ(typ); + hints := [build_hint(p, typeSignature), ...hints^]; + }; + | _ => () + }; + }; }); Iterator.iter_typed_program(program); hints^; diff --git a/compiler/src/typed/typedtreeIter.re b/compiler/src/typed/typedtreeIter.re index 557021ab9..5a702c874 100644 --- a/compiler/src/typed/typedtreeIter.re +++ b/compiler/src/typed/typedtreeIter.re @@ -30,8 +30,8 @@ module type IteratorArgument = { let leave_core_type: core_type => unit; let leave_toplevel_stmt: toplevel_stmt => unit; - let enter_bindings: (rec_flag, mut_flag) => unit; - let enter_binding: value_binding => unit; + let enter_bindings: (rec_flag, mut_flag, bool) => unit; + let enter_binding: (value_binding, bool) => unit; let leave_binding: value_binding => unit; let leave_bindings: (rec_flag, mut_flag) => unit; @@ -74,16 +74,16 @@ module MakeIterator = Iter.leave_core_type(ct); } - and iter_binding = ({vb_pat, vb_expr} as vb) => { - Iter.enter_binding(vb); + and iter_binding = (~toplevel=false, {vb_pat, vb_expr} as vb) => { + Iter.enter_binding(vb, toplevel); iter_pattern(vb_pat); iter_expression(vb_expr); Iter.leave_binding(vb); } - and iter_bindings = (rec_flag, mut_flag, binds) => { - Iter.enter_bindings(rec_flag, mut_flag); - List.iter(iter_binding, binds); + and iter_bindings = (~toplevel=false, rec_flag, mut_flag, binds) => { + Iter.enter_bindings(rec_flag, mut_flag, toplevel); + List.iter(iter_binding(~toplevel), binds); Iter.leave_bindings(rec_flag, mut_flag); } @@ -132,7 +132,7 @@ module MakeIterator = | TTopModule({tmod_statements}) => iter_toplevel_stmts(tmod_statements) | TTopExpr(e) => iter_expression(e) | TTopLet(recflag, mutflag, binds) => - iter_bindings(recflag, mutflag, binds) + iter_bindings(recflag, mutflag, binds, ~toplevel=true) }; Iter.leave_toplevel_stmt(stmt); } @@ -206,7 +206,7 @@ module MakeIterator = | TExpIdent(_) | TExpConstant(_) => () | TExpLet(recflag, mutflag, binds) => - iter_bindings(recflag, mutflag, binds) + iter_bindings(recflag, mutflag, binds, ~toplevel=false) | TExpLambda(branches, _) => iter_match_branches(branches) | TExpApp(exp, _, args) => iter_expression(exp); @@ -274,8 +274,8 @@ module DefaultIteratorArgument: IteratorArgument = { let enter_expression = _ => (); let enter_core_type = _ => (); let enter_toplevel_stmt = _ => (); - let enter_bindings = (_, _) => (); - let enter_binding = _ => (); + let enter_bindings = (_, _, _) => (); + let enter_binding = (_, _) => (); let enter_data_declaration = _ => (); let enter_data_declarations = () => (); diff --git a/compiler/src/typed/typedtreeIter.rei b/compiler/src/typed/typedtreeIter.rei index 498467162..b1a3abf55 100644 --- a/compiler/src/typed/typedtreeIter.rei +++ b/compiler/src/typed/typedtreeIter.rei @@ -30,8 +30,8 @@ module type IteratorArgument = { let leave_core_type: core_type => unit; let leave_toplevel_stmt: toplevel_stmt => unit; - let enter_bindings: (rec_flag, mut_flag) => unit; - let enter_binding: value_binding => unit; + let enter_bindings: (rec_flag, mut_flag, bool) => unit; + let enter_binding: (value_binding, bool) => unit; let leave_binding: value_binding => unit; let leave_bindings: (rec_flag, mut_flag) => unit;