Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type syntax not stable under bracketing? #909

Open
martinberger opened this issue Jan 26, 2025 · 5 comments
Open

Type syntax not stable under bracketing? #909

martinberger opened this issue Jan 26, 2025 · 5 comments

Comments

@martinberger
Copy link

martinberger commented Jan 26, 2025

Not sure this is a bug or feature, but (in Sail 0.17 (sail @ opam-v2.3.0) ) we can do

val f : unit -> unit

But not

val f : (unit -> unit) // ERROR 

I imagine that this comes from function types for functions being enforced during parsing, not type-checking. But it surprised me: in most programming languages one can always bracket expressions, whether types or program expressions.

Could you clarify?

@Alasdair
Copy link
Collaborator

Yes, because Sail is first-order function types are only allowed in specific places in the grammar - therefore a function type is not currently an expression you can use anywhere a type is expected, for example

vector('n, int -> int)

val f : int -> int -> int

are both parse errors.

It is sometimes a good idea to refactor the parser to be more permissive, and then reject the bad cases later with a more bespoke and descriptive error message.

If we did want to refactor like that I think the real motivation would be function type synonyms which aren't currently possible due to the syntactic restrictions on function types.

@martinberger
Copy link
Author

Yes, I also noticed that function type synonyms are not possible, and was about to raise an issue here.

@Alasdair
Copy link
Collaborator

There are some more fundamental issues we'd have to solve to make it work. The first-orderness assumption is pretty baked-in to the design of the type system and grammar all the way back to the first few commits in this repository.

@martinberger
Copy link
Author

martinberger commented Jan 26, 2025

Can the first order assumption not simply be enforced by the type checker? It's a natural division of labour and clean modularisation: parser checks syntactic correctness, the subsequent type checker, assuming grammatical correctness, checks type-and kind correctness? (I am probably overlooking some subtlety!)

@Alasdair
Copy link
Collaborator

Alasdair commented Jan 26, 2025

It's a trade off. Right now the fact that function types are not nested within other types is guaranteed by the structure of the AST. That means it's impossible to even represent a non first order program. Sail backends downstream of the type checker don't even have to consider the possibility that they'll see an unexpected function type anwhere, they can just follow the structure of the AST and rely on OCaml's pattern completeness checker to cover all cases.

For properties of the AST that are just enforced by type-checking rules (or AST->AST rewrites), that's something you have to hold in your head while writing Sail backends, so there's more cognitive load on the developer to remember all the invariants.

So the trade off is a more flexible AST usually gets you better error messages and reduces syntactic ambiguity, but a more restrictive AST means you can leverage the type-system of the implementation language to enforce invariants. This is why in Sail we have two ASTs, the Parse_ast type that represents the AST just after parsing, then the Ast type that is a bit simpler and has a lot of syntactic sugar removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants