FuelLabs / sway

🌴 Empowering everyone to build reliable and efficient smart contracts.
https://docs.fuel.network/docs/sway/
Apache License 2.0
62.76k stars 5.36k forks source link

Remove the module kind declaration (i.e. `script;`, `contract;`, etc) from Sway files in favour of a forc manifest field #4244

Open mitchmindtree opened 1 year ago

mitchmindtree commented 1 year ago

Motivation

Currently, we declare a "program type" at the start of each Sway file.

This currently has a few issues:

  1. All files in a project can only be library other than the project root, which can be any of the library;, script;, contract; or predicate; types. This means users are often forced to declare the library type unnecessarily, as we should be able to infer this type based on whether the file is a submodule (i.e. not the root). The compiler only needs to know the intended program type for a package as a whole (i.e. a whole tree of modules).

  2. Currently forc has to parse the root src file just to check the program type (it's not safe to just grab the first line as a user might have combinations of whitespace, comments and now module-level comments preceding the declaration).

To address these concerns, we might consider moving the program type declaration field from the module level (i.e. Sway files) to the forc manifest, and treating the intended program type as an input to the compilation process.

For now, this could be an entry under the [project] table, e.g.

[project]
authors = ["name"]
entry = "main.sw"
license = "Apache-2.0"
name = "forc-pkgs"
type = "contract" # Indicates the contract program type. Could also be "script", "library" or "predicate".

Eventually we may wish to add support for individual projects to specify multiple targets, similar to how Rust allows for specifying multiple [bin] entry points for a single crate today. For now, I think a field under the [project] table would likely enable the simplest transition from the current approach.

Implementation

Steps of implementation may look something like the following:

References

Previously mentioned:

and more places I'm sure I'm missing!

mohammadfawaz commented 1 year ago

Relevant: https://github.com/FuelLabs/sway/issues/2428

nfurfaro commented 1 year ago

Would this approach of specifying the program type in the manifest suffice to disambiguate between script and predicate types? I guess you wouldn't know from reading just the file which type you're looking at, but assuming you can still only have one of these types per forc "package", the manifest would tell you what you need to know.

It bugs me a bit that reading the src file alone would not tell me what type of program it is. I think it's worth considering the ideas of either renaming main() to script()/predicate(), or using an annotation like:

#[predicate()]
fn main() -> bool {...
arboleya commented 1 year ago

Maybe unrelated, but could we also have this information (program type) present on the Json ABI?

Currently, on the TS-SDK Typegen land, we ask users to specify the program type explicitly.

Ideally, this could be automatically inferred from the ABI.

cc @camsjams

mitchmindtree commented 1 year ago

Would this approach of specifying the program type in the manifest suffice to disambiguate between script and predicate types?

Yes

I guess you wouldn't know from reading just the file which type you're looking at, but assuming you can still only have one of these types per forc "package", the manifest would tell you what you need to know.

Yes this would be closer to Rust's approach, where you can specify both lib and one or more bin targets for a single crate. In our case rather than just lib or bin, we'd have library, script, predicate and contract. The proposal above is for just specifying a single target type under a type field, but later we could potentially enable specifying multiple targets with different entry points similar to how Rust does. There are normally ways to work around this though (e.g. split out different packages for different targets) so I don't think the multi-target approach should be a big priority.

It bugs me a bit that reading the src file alone would not tell me what type of program it is.

It's worth keeping in mind that today, we have the opposite problem, i.e. you can't know what the type of a package is just by reading it's manifest. It's arguably more important at the manifest level, as there are all sorts of places where forc can use that information before parsing begins (e.g. for forc deploy or forc run, validating contract dependency declarations, etc).

nfurfaro commented 1 year ago

It's arguably more important at the manifest level, as there are all sorts of places where forc can use that information before parsing begins

Yeah, makes sense.