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

Expand ameba's functionality with semantic information #513

Open
nobodywasishere opened this issue Nov 24, 2024 · 2 comments
Open

Expand ameba's functionality with semantic information #513

nobodywasishere opened this issue Nov 24, 2024 · 2 comments

Comments

@nobodywasishere
Copy link
Contributor

Currently ameba uses only the stdlib parser in order to provide an AST for the rules to operate over. This is useful, but limits the kinds of things that ameba can be used for. This is an issue to discuss if semantic information to ameba, what that would look like, and what are the downsides / tradeoffs to different approaches. For instance, if we added a top level semantic pass:

  • That would require operating at the shard-level instead of individual files (at least for semantic-level rules)
    • Opens up to more semantic compiler errors, but I think the parser rules and top-level semantic rules should operate independently
    • Need to figure out how this would work with linting while typing for the vscode extension, as there may be multiple files open with changes in them, and we'd want ameba to operate on those instead of the ones saved on disk
    • How would the top-level semantic interact with the Excluded in .ameba.yml?
  • One of amebas benefits right now is how fast it is, we should profile this to see how worse it is
    • We'd be going from parsing singular files to parsing all files in stdlib/lib/current shard + semantic pass
  • What would we be able to do with a top-level semantic that we can't now?
    • Namespace collision detection: Incorrect scope after including **::Serializable crystal-lang/crystal#6194
    • (Maybe) type unsafe equality if both sides of comparison are typed
    • (Maybe) type unsafe hash key types if things are explicitly typed (see crystal-lang/crystal#8893)
    • Typing/{Instance,Class}VarTypeRestriction - currently running into potential issues where an instance var could be typed somewhere, but just not in the current file, leading to a failure
    • Know what calls are to methods or to macros, for better Lint/UnusedVariable and others
@nobodywasishere
Copy link
Contributor Author

Other rule ideas possible with top level semantic (not saying these should be done, but that they could be):

  • Lint/NoReopen - disallow reopening of classes (or maybe monkey-patching stdlib classes/structs/etc)
  • Documentation/OverwrittenDocs - warn when adding documentation to a class/module/lib in multiple places which ones will be ignored
  • Documentation/UselessShowdocDirective - warn when a :showdoc: directive doesn't work (once those are added)

@nobodywasishere
Copy link
Contributor Author

nobodywasishere commented Dec 29, 2024

Need to figure out how this would work with linting while typing for the vscode extension, as there may be multiple files open with changes in them, and we'd want ameba to operate on those instead of the ones saved on disk

This will just need to be left up to an LSP using ameba, and not something we should worry about.

How would the top-level semantic interact with the Excluded in .ameba.yml?

Any issues found in a file that's excluded should be ignored, like how it is currently (except for Lint/SyntaxError and Lint/SemanticError). Additionally, it should automatically exclude any file not in the current directory, or inside 'lib/', to prevent errors from stdlib or shards popping up. (Can't just limit to src/ as not all projects limit crystal code to src/).


For another rule idea, I run into this issue a lot:

class MessageHandler
  def on_request(msg)
    # generic message handling
  end
  
  def on_request(msg : SpecificRequestType)
    # specific message handling
  end
end

If I accidentally mistype SpecificRequestType, I won't know I got it wrong until I actually run the application. It would be really useful to have a Lint/UnknownType rule that checks that all explicitly typed things actually exist, and this should only require a top-level semantic.

One of the biggest issues I see with Crystal currently is that no semantic analysis is done to code that isn't used. This means when developing library code, unless you write good specs (and know you have to write good specs), you can have semantic issues in your code and have no idea until someone else goes to use it. It would be useful to have some level of semantic analysis for methods, such that explicitly typed things can be checked to make sure their methods actually exist. For example:

def hello(a : String)
  a.method_doesnt_exist
  # ^^^^^^^^^^^^^^^^^^^ error: `String` doesn't have method `method_doesnt_exist`
end

If the rule runs into a method that isn't typed, we don't do anything beyond that. The only types this should infer is from literals or methods whose return types are specified. It should be fast, not exhaustive.

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

No branches or pull requests

2 participants