Skip to content

Commit

Permalink
Add a test for the private keyword
Browse files Browse the repository at this point in the history
Improve the error message for trying to use a private definition
from a module that hasn't been required
  • Loading branch information
Alasdair committed Oct 4, 2024
1 parent 8a257af commit f9dd361
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 14 deletions.
2 changes: 1 addition & 1 deletion editors/sail-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
'("val" "outcome" "function" "type" "struct" "union" "enum" "let" "var" "if" "then" "by"
"else" "match" "in" "return" "register" "ref" "forall" "operator" "effect"
"overload" "cast" "sizeof" "constant" "constraint" "default" "assert" "newtype" "from"
"pure" "monadic" "infixl" "infixr" "infix" "scattered" "end" "try" "catch" "and" "to"
"pure" "monadic" "infixl" "infixr" "infix" "scattered" "end" "try" "catch" "and" "to" "private"
"throw" "clause" "as" "repeat" "until" "while" "do" "foreach" "bitfield"
"mapping" "where" "with" "implicit" "instantiation" "impl" "forwards" "backwards"))

Expand Down
3 changes: 2 additions & 1 deletion src/lib/type_check.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4482,7 +4482,7 @@ let check_fundef env def_annot (FD_aux (FD_function (recopt, tannot_opt, funcls)
(* No val, so get the function type from annotations attached to clauses *)
let bind = infer_funtyp l env tannot_opt funcls in
(None, bind, env)
| exception Type_error (l, Err_not_in_scope (_, scope_l, item_scope, into_scope, priv)) ->
| exception Type_error (l, Err_not_in_scope (_, scope_l, item_scope, into_scope, is_opened, priv)) ->
(* If we defined the function type with val in another module, but didn't require it. *)
let reason = if priv then "private." else "not in scope." in
typ_raise l
Expand All @@ -4491,6 +4491,7 @@ let check_fundef env def_annot (FD_aux (FD_function (recopt, tannot_opt, funcls)
scope_l,
item_scope,
into_scope,
is_opened,
priv
)
)
Expand Down
5 changes: 3 additions & 2 deletions src/lib/type_env.ml
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,15 @@ let filter_items_with f env bindings =
let filter_items env bindings = filter_items_with (fun x -> x) env bindings

let err_not_in_scope env msg l item =
let is_opened = Project.ModSet.mem item.mod_id env.opened in
match env.global.modules with
| None -> Err_not_in_scope (msg, l, None, None, is_private item.visibility)
| None -> Err_not_in_scope (msg, l, None, None, is_opened, is_private item.visibility)
| Some proj ->
let module_name_opt mod_id =
if Project.valid_module_id proj mod_id then Some (Project.module_name proj mod_id) else None
in
Err_not_in_scope
(msg, l, module_name_opt item.mod_id, module_name_opt env.current_module, is_private item.visibility)
(msg, l, module_name_opt item.mod_id, module_name_opt env.current_module, is_opened, is_private item.visibility)

let get_item_with_loc get_loc l env item =
if item_in_scope env item then item.item
Expand Down
20 changes: 12 additions & 8 deletions src/lib/type_error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ let message_of_type_error type_error =
None
)
| Err_no_num_ident id -> (Line ("No num identifier " ^ string_of_id id), None)
| Err_not_in_scope (explanation, Some l, item_scope, into_scope, priv) ->
| Err_not_in_scope (explanation, Some l, item_scope, into_scope, is_opened, priv) ->
let suggest, in_mod, add_requires_here =
match (item_scope, into_scope) with
| None, None -> ("Try bringing the following into scope:", "", [])
Expand Down Expand Up @@ -496,16 +496,20 @@ let message_of_type_error type_error =
),
None
)
else
else (
let private_not_opened =
if not is_opened then [Line "The module containing this definition is also not required in this context"]
else []
in
( Seq
[
Line (Option.value ~default:"Cannot use private definition" explanation);
Line "";
Location ("", Some ("private definition here" ^ in_mod), l, Seq []);
],
([Line (Option.value ~default:"Cannot use private definition" explanation)]
@ private_not_opened
@ [Line ""; Location ("", Some ("private definition here" ^ in_mod), l, Seq [])]
),
None
)
| Err_not_in_scope (explanation, None, _, _, _) -> (Line (Option.value ~default:"Not in scope" explanation), None)
)
| Err_not_in_scope (explanation, None, _, _, _, _) -> (Line (Option.value ~default:"Not in scope" explanation), None)
in
to_message type_error

Expand Down
2 changes: 1 addition & 1 deletion src/lib/type_error.mli
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type type_error =
| Err_other of string
| Err_inner of type_error * Parse_ast.l * string * type_error
| Err_not_in_scope of
string option * Parse_ast.l option * string Project.spanned option * string Project.spanned option * bool
string option * Parse_ast.l option * string Project.spanned option * string Project.spanned option * bool * bool
| Err_instantiation_info of int * type_error
| Err_function_arg of Parse_ast.l * typ * type_error
| Err_no_function_type of { id : id; functions : (typquant * typ) Bindings.t }
Expand Down
2 changes: 1 addition & 1 deletion src/lib/type_internal.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type type_error =
| Err_other of string
| Err_inner of type_error * Parse_ast.l * string * type_error
| Err_not_in_scope of
string option * Parse_ast.l option * string Project.spanned option * string Project.spanned option * bool
string option * Parse_ast.l option * string Project.spanned option * string Project.spanned option * bool * bool
| Err_instantiation_info of int * type_error
| Err_function_arg of Parse_ast.l * typ * type_error
| Err_no_function_type of { id : id; functions : (typquant * typ) Bindings.t }
Expand Down
9 changes: 9 additions & 0 deletions test/typecheck/project/fail_private.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Type error:
project/private/bmod.sail:4.4-7:
4 | foo("Cannot be called")
 | ^-^
 | Cannot use private definition
 |
 | project/private/amod.sail:3.17-20:
 | 3 |private function foo(message : string) -> unit = {
 |  | ^-^ private definition here in A
9 changes: 9 additions & 0 deletions test/typecheck/project/fail_private.sail_project
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

A {
files private/amod.sail
}

B {
requires A
files private/bmod.sail
}
10 changes: 10 additions & 0 deletions test/typecheck/project/fail_private_nr.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Type error:
project/private/bmod.sail:4.4-7:
4 | foo("Cannot be called")
 | ^-^
 | Cannot use private definition
 | The module containing this definition is also not required in this context
 |
 | project/private/amod.sail:3.17-20:
 | 3 |private function foo(message : string) -> unit = {
 |  | ^-^ private definition here in A
8 changes: 8 additions & 0 deletions test/typecheck/project/fail_private_nr.sail_project
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

A {
files private/amod.sail
}

B {
files private/bmod.sail
}
5 changes: 5 additions & 0 deletions test/typecheck/project/private/amod.sail
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$include <string.sail>

private function foo(message : string) -> unit = {
print_endline(message)
}
5 changes: 5 additions & 0 deletions test/typecheck/project/private/bmod.sail
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
val main : unit -> unit

function main() = {
foo("Cannot be called")
}

0 comments on commit f9dd361

Please sign in to comment.