Skip to content

Commit

Permalink
feat(compiler): Providing, including, reproviding exceptions (#1849)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-snezhko committed Jan 28, 2024
1 parent 00abee8 commit 687e747
Show file tree
Hide file tree
Showing 26 changed files with 266 additions and 22 deletions.
8 changes: 7 additions & 1 deletion compiler/src/formatting/format.re
Original file line number Diff line number Diff line change
Expand Up @@ -3917,7 +3917,8 @@ and print_expression_inner =
switch (item) {
| PUseValue({loc})
| PUseModule({loc})
| PUseType({loc}) => loc
| PUseType({loc})
| PUseException({loc}) => loc
};
};

Expand Down Expand Up @@ -3961,6 +3962,8 @@ and print_expression_inner =
Doc.concat([Doc.text("module "), item_name(name, alias)])
| PUseType({name, alias}) =>
Doc.concat([Doc.text("type "), item_name(name, alias)])
| PUseException({name, alias}) =>
Doc.concat([Doc.text("exception "), item_name(name, alias)])
};
};

Expand Down Expand Up @@ -5068,6 +5071,7 @@ let rec toplevel_print =
switch (item) {
| PProvideValue({loc})
| PProvideModule({loc})
| PProvideException({loc})
| PProvideType({loc}) => loc
};
};
Expand Down Expand Up @@ -5112,6 +5116,8 @@ let rec toplevel_print =
Doc.concat([Doc.text("module "), item_name(name, alias)])
| PProvideType({name, alias}) =>
Doc.concat([Doc.text("type "), item_name(name, alias)])
| PProvideException({name, alias}) =>
Doc.concat([Doc.text("exception "), item_name(name, alias)])
};
};

Expand Down
1 change: 1 addition & 0 deletions compiler/src/language_server/definition.re
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ let process =
| [Pattern({definition}), ..._]
| [Type({definition}), ..._]
| [Declaration({definition}), ..._]
| [Exception({definition}), ..._]
| [Module({definition}), ..._] =>
switch (definition) {
| None => send_no_result(~id)
Expand Down
13 changes: 13 additions & 0 deletions compiler/src/language_server/hover.re
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ let declaration_lens = (ident: Ident.t, decl: Types.type_declaration) => {
grain_type_code_block(Printtyp.string_of_type_declaration(~ident, decl));
};

let exception_declaration_lens =
(ident: Ident.t, ext: Types.extension_constructor) => {
grain_type_code_block(
Printtyp.string_of_extension_constructor(~ident, ext),
);
};

let process =
(
~id: Protocol.message_id,
Expand Down Expand Up @@ -161,6 +168,12 @@ let process =
~range=Utils.loc_to_range(loc),
declaration_lens(ident, decl),
)
| [Exception({ident, ext, loc}), ..._] =>
send_hover(
~id,
~range=Utils.loc_to_range(loc),
exception_declaration_lens(ident, ext),
)
| [Module({path, decl, loc}), ..._] =>
send_hover(~id, ~range=Utils.loc_to_range(loc), module_lens(decl))
| _ => send_no_result(~id)
Expand Down
21 changes: 21 additions & 0 deletions compiler/src/language_server/sourcetree.re
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ module type Sourcetree = {
loc: Location.t,
definition: option(Location.t),
})
| Exception({
ident: Ident.t,
ext: Types.extension_constructor,
loc: Location.t,
definition: option(Location.t),
})
| Module({
path: Path.t,
decl: Types.module_declaration,
Expand Down Expand Up @@ -236,6 +242,12 @@ module Sourcetree: Sourcetree = {
loc: Location.t,
definition: option(Location.t),
})
| Exception({
ident: Ident.t,
ext: Types.extension_constructor,
loc: Location.t,
definition: option(Location.t),
})
| Module({
path: Path.t,
decl: Types.module_declaration,
Expand Down Expand Up @@ -387,6 +399,15 @@ module Sourcetree: Sourcetree = {
definition: Some(value.val_loc),
}),
)
| TUseException({name, ext, loc}) => (
loc_to_interval(loc),
Exception({
ident: Ident.create(name),
ext,
loc,
definition: Some(ext.ext_loc),
}),
)
}
},
items,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/middle_end/linearize.re
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let compile_constructor_tag =
fun
| CstrConstant(i) => i
| CstrBlock(i) => i
| CstrExtension(i, _, _) => i
| CstrExtension(i, _, _, _) => i
| CstrUnboxed =>
failwith("compile_constructor_tag: cannot compile CstrUnboxed")
);
Expand Down
12 changes: 12 additions & 0 deletions compiler/src/parsing/ast_mapper.re
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ module E = {
alias: Option.map(map_identifier(sub), alias),
loc: sub.location(sub, loc),
})
| PUseException({name, alias, loc}) =>
PUseException({
name: map_identifier(sub, name),
alias: Option.map(map_identifier(sub), alias),
loc: sub.location(sub, loc),
})
| PUseModule({name, alias, loc}) =>
PUseModule({
name: map_identifier(sub, name),
Expand Down Expand Up @@ -432,6 +438,12 @@ module Pr = {
alias: Option.map(map_identifier(sub), alias),
loc: sub.location(sub, loc),
})
| PProvideException({name, alias, loc}) =>
PProvideException({
name: map_identifier(sub, name),
alias: Option.map(map_identifier(sub), alias),
loc: sub.location(sub, loc),
})
| PProvideModule({name, alias, loc}) =>
PProvideModule({
name: map_identifier(sub, name),
Expand Down
24 changes: 24 additions & 0 deletions compiler/src/parsing/parser.messages
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ program: MODULE UIDENT EOL FROM UIDENT USE LBRACE MODULE YIELD

Expected an uppercase type identifier.

program: MODULE UIDENT EOL FROM UIDENT USE LBRACE EXCEPTION YIELD
##
## Ends in an error in state: 57.
##
## use_item -> EXCEPTION . aliasable(uid) [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## EXCEPTION
##

Expected an uppercase exception identifier.

program: MODULE UIDENT EOL PROVIDE LBRACE MODULE UIDENT YIELD
##
## Ends in an error in state: 49.
Expand Down Expand Up @@ -558,6 +570,18 @@ program: MODULE UIDENT EOL PROVIDE LBRACE TYPE YIELD

Expected a type identifier to provide.

program: MODULE UIDENT EOL PROVIDE LBRACE EXCEPTION YIELD
##
## Ends in an error in state: 825.
##
## provide_item -> EXCEPTION . aliasable(uid) [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## EXCEPTION
##

Expected an exception identifier to provide.

program: MODULE UIDENT EOL FROM UIDENT USE LBRACE LIDENT AS LIDENT YIELD
##
## Ends in an error in state: 62.
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/parsing/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ aliasable(X):
use_item:
| TYPE aliasable(uid) { PUseType { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| MODULE aliasable(uid) { PUseModule { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| EXCEPTION aliasable(uid) { PUseException { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(lid) { PUseValue { name=fst $1; alias = snd $1; loc=to_loc $loc} }

use_items:
Expand Down Expand Up @@ -372,6 +373,7 @@ data_declaration_stmts:
provide_item:
| TYPE aliasable(uid) { PProvideType { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| MODULE aliasable(uid) { PProvideModule { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| EXCEPTION aliasable(uid) { PProvideException { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(lid) { PProvideValue { name=fst $1; alias = snd $1; loc=to_loc $loc} }

provide_items:
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/parsing/parsetree.re
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ and use_item =
alias: option(loc(Identifier.t)),
loc: Location.t,
})
| PUseException({
name: loc(Identifier.t),
alias: option(loc(Identifier.t)),
loc: Location.t,
})
| PUseModule({
name: loc(Identifier.t),
alias: option(loc(Identifier.t)),
Expand Down Expand Up @@ -595,6 +600,11 @@ type provide_item =
alias: option(loc(Identifier.t)),
loc: Location.t,
})
| PProvideException({
name: loc(Identifier.t),
alias: option(loc(Identifier.t)),
loc: Location.t,
})
| PProvideModule({
name: loc(Identifier.t),
alias: option(loc(Identifier.t)),
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/parsing/parsetree_iter.re
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ and iter_provide = (hooks, items) => {
item => {
switch (item) {
| PProvideType({name, alias, loc})
| PProvideException({name, alias, loc})
| PProvideModule({name, alias, loc})
| PProvideValue({name, alias, loc}) =>
iter_ident(hooks, name);
Expand Down Expand Up @@ -290,6 +291,7 @@ and iter_expression =
item => {
switch (item) {
| PUseType({name, alias, loc})
| PUseException({name, alias, loc})
| PUseModule({name, alias, loc})
| PUseValue({name, alias, loc}) =>
iter_ident(hooks, name);
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/parsing/well_formedness.re
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ let no_local_include = (errs, super) => {
type provided_multiple_times_ctx = {
modules: Hashtbl.t(string, unit),
types: Hashtbl.t(string, unit),
exceptions: Hashtbl.t(string, unit),
values: Hashtbl.t(string, unit),
};

Expand Down Expand Up @@ -666,6 +667,7 @@ let provided_multiple_times = (errs, super) => {
{
modules: Hashtbl.create(64),
types: Hashtbl.create(64),
exceptions: Hashtbl.create(64),
values: Hashtbl.create(64),
},
]);
Expand All @@ -676,6 +678,7 @@ let provided_multiple_times = (errs, super) => {
{
modules: Hashtbl.create(64),
types: Hashtbl.create(64),
exceptions: Hashtbl.create(64),
values: Hashtbl.create(64),
},
...ctx^,
Expand All @@ -689,7 +692,7 @@ let provided_multiple_times = (errs, super) => {
};

let enter_toplevel_stmt = ({ptop_desc: desc} as top) => {
let {values, modules, types} = List.hd(ctx^);
let {values, modules, types, exceptions} = List.hd(ctx^);
switch (desc) {
| PTopModule(Provided | Abstract, {pmod_name, pmod_loc}) =>
if (Hashtbl.mem(modules, pmod_name.txt)) {
Expand Down Expand Up @@ -774,6 +777,13 @@ let provided_multiple_times = (errs, super) => {
} else {
Hashtbl.add(types, name, ());
};
| PProvideException({name, alias, loc}) =>
let (_, name) = apply_alias(name, alias);
if (Hashtbl.mem(exceptions, name)) {
errs := [ProvidedMultipleTimes(name, loc), ...errs^];
} else {
Hashtbl.add(exceptions, name, ());
};
| PProvideModule({name, alias, loc}) =>
let (_, name) = apply_alias(name, alias);
if (Hashtbl.mem(modules, name)) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/typed/datarepr.re
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ let extension_descr = (path_ext, ext) => {
cstr_existentials: existentials,
cstr_args,
cstr_arity: List.length(cstr_args),
cstr_tag: CstrExtension(ext.ext_name.stamp, path_ext, cstr_ext_type),
cstr_tag: CstrExtension(ext.ext_name.stamp, path_ext, cstr_ext_type, ext),
cstr_consts: (-1),
cstr_nonconsts: (-1),
cstr_loc: ext.ext_loc,
Expand Down
35 changes: 35 additions & 0 deletions compiler/src/typed/env.re
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type error =
| Value_not_found_in_module(Location.t, string, string)
| Module_not_found_in_module(Location.t, string, string, option(string))
| Type_not_found_in_module(Location.t, string, string)
| Exception_not_found_in_module(Location.t, string, string)
| Illegal_value_name(Location.t, string)
| Cyclic_dependencies(string, dependency_chain);

Expand Down Expand Up @@ -941,6 +942,7 @@ let check_pers_struct = (~loc, name, filename) =>
| Value_not_found_in_module(_) => assert(false)
| Module_not_found_in_module(_) => assert(false)
| Type_not_found_in_module(_) => assert(false)
| Exception_not_found_in_module(_) => assert(false)
| Illegal_value_name(_) => assert(false)
| Cyclic_dependencies(_) => assert(false)
};
Expand Down Expand Up @@ -2222,6 +2224,37 @@ let use_partial_signature = (root, items, env0) => {
);
TUseType({name: new_name, declaration: decl, loc});
};
| PUseException({name, alias, loc}) =>
let (old_name, new_name) = apply_alias(name, alias);
switch (Tbl.find(old_name, comps.comp_constrs)) {
| exception Not_found =>
error(
Exception_not_found_in_module(
name.loc,
old_name,
Path.name(root),
),
)
| cstrs =>
let (ext, cstr_name) =
List.find_map(
cstr =>
switch (cstr.cstr_tag) {
| CstrExtension(_, _, _, ext) =>
Some((ext, cstr.cstr_name))
| _ => None
},
cstrs,
)
|> Option.get;
new_comps.comp_constrs =
Tbl.add(
new_name,
Tbl.find(cstr_name, comps.comp_constrs),
new_comps.comp_constrs,
);
TUseException({name: new_name, ext, loc});
};
}
},
items,
Expand Down Expand Up @@ -2609,6 +2642,8 @@ let report_error = ppf =>
)
| Type_not_found_in_module(_, name, path) =>
fprintf(ppf, "Unbound type %s in module %s", name, path)
| Exception_not_found_in_module(_, name, path) =>
fprintf(ppf, "Unbound exception %s in module %s", name, path)
| Cyclic_dependencies(dep, chain) =>
fprintf(
ppf,
Expand Down
1 change: 1 addition & 0 deletions compiler/src/typed/env.rei
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type error =
| Value_not_found_in_module(Location.t, string, string)
| Module_not_found_in_module(Location.t, string, string, option(string))
| Type_not_found_in_module(Location.t, string, string)
| Exception_not_found_in_module(Location.t, string, string)
| Illegal_value_name(Location.t, string)
| Cyclic_dependencies(string, dependency_chain);

Expand Down
6 changes: 5 additions & 1 deletion compiler/src/typed/printtyp.re
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ let tree_of_extension_constructor = (id, ext, es) => {
let extension_constructor = (id, ppf, ext) =>
Oprint.out_sig_item^(
ppf,
tree_of_extension_constructor(id, ext, TExtFirst),
tree_of_extension_constructor(id, ext, TExtException),
);

let extension_only_constructor = (id, ppf, ext) => {
Expand All @@ -1035,6 +1035,10 @@ let extension_only_constructor = (id, ppf, ext) => {
Format.fprintf(ppf, "@[<hv>%a@]", Oprint.out_constr^, (name, args, None));
};

let string_of_extension_constructor = (~ident, ext) => {
asprintf("%a", extension_constructor(ident), ext);
};

/* Print a value declaration */
let tree_of_value_description = (id, decl) => {
let id = Ident.name(id);
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/typed/printtyp.rei
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ let tree_of_type_declaration:
let type_declaration: (Ident.t, formatter, type_declaration) => unit;
let string_of_type_declaration: (~ident: Ident.t, type_declaration) => string;
let extension_constructor: (Ident.t, formatter, extension_constructor) => unit;
let string_of_extension_constructor:
(~ident: Ident.t, extension_constructor) => string;
let tree_of_module:
(Ident.t, ~ellipsis: bool=?, module_type, rec_status) => out_sig_item;
let modtype: (formatter, module_type) => unit;
Expand Down
Loading

0 comments on commit 687e747

Please sign in to comment.