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

How to handle all cases... #52

Closed
mrolle45 opened this issue Aug 15, 2022 · 1 comment
Closed

How to handle all cases... #52

mrolle45 opened this issue Aug 15, 2022 · 1 comment

Comments

@mrolle45
Copy link

I propose that you handle all type comments in the target program. That means with and for statements and all degrees of complexity in assignments. Comments that are ill-formed should be reported and left alone. Otherwise the comments will be stripped and the appropriate annotations inserted to replace them.
I have a package scopetools which can provide lots of help. It is still under development. I'd like to work with you in enhancing scopetools and integrating it into com2ann, so please let me know if you are interested. It can find all the type comments and their containing scopes, and the owning scopes for global and nonlocal names. It can split complex target assignments, or type comments, into simpler items (names, attributes, and subscripts).

Here's the basic strategy:

  • Function defs and args are fine. However, if there is an annotation for one of the arguments, the type from the function comment is added to the arg, resulting in two annotations, a SyntaxError.
    Other than that...

Every statement has a target (or multiple targets for an assignment) and a type. With multiple targets, the same type applies to each target. The type is the type comment, parsed as an expression. Annotating the target with the type is the same process as assigning the type to the target. That is, if the target is a packing (a tuple or list of subtargets), the subtargets are annotated with subtypes derived from iterating on the type, taking into account a possible starred subtarget. If the number of subtypes is wrong, this is a malformed type comment, just like an assignment statement. This is done recursively.
The result is that you have a set of (sub)targets and (sub)types, where each target is an ast.Name, ast.Subscript, or ast.Attribute.
Attribute and Subscript annotations can just be inserted before the original statement.
Name annotations are more complicated:

  • If the name is declared nonlocal or global (but not at the module level), then a bare annotation (that is, without an assigned value) is placed in the owning scope (the module or some enclosing function) just before the scope definition which contains the original statement. This way, if the scope definition is unreachable, then a type checker will ignore the new annotation.
  • If the statement is a simple assignment with one target and no subtargets, then the annotation is inserted after the name.
  • Otherwise, a bare annotation is inserted before the statement.

The target for a statement is as follows:

  • Assignment: target [ = target ... ] = value # type: typeexpr
    Each target is a target and annotated with the entiretypeexpr.
    Examples:
    w, (x.a, (y[0], z)) = value # type: t1, (t2, (t3, t4)). This annotates w, x.a, y[0], and z with t1, t2, t3, and t4, resp.
    t = w, (x.a, (y[0], z)) = value # type: t1, (t2, (t3, t4)). Same and annotates t with (t1, (t2, (t3, t4))).

  • For: for target in iterable: # type: typeexpr
    target is the target.

  • With: with context [ as target ] [ , context [as target] ... ]: # type: typeexpr

    • With no as target clause, this statement is ignored.
    • With exactly one as target clause, target is the target.
    • With more than one, then target is (target, target [ , target ... ]). The tuple contains only the targets from all the as target clauses that are present.

    Examples:
    with c1 as t1, c2, c3 as t3.x: # type: type1, type3:. This annotates t1 with type1 and t3.x with type3.
    with c1 as t1, c2, c3: # type: type1:. This annotates t1 with type1.
    with c1 as t1: # type: type1:. This annotates t1 with type1.
    with c1 as t1: # type: type1, type2:. This annotates t1 with (type1, type2). The tuple is not unpacked.

@ilevkivskyi
Copy link
Owner

There are already existing issues for tuple type comments #41 and fop/with statements #9. These are the cases I am interested in. I am closing this issue for now, propose to discuss this in those two issues instead.

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