KEMBAR78
Tag Anys with their provenance by ilinum · Pull Request #3786 · python/mypy · GitHub
Skip to content

Conversation

ilinum
Copy link
Collaborator

@ilinum ilinum commented Aug 1, 2017

This PR tags each instance of AnyType with where it comes from.
Each Any can be one (and only one) of the following:

  • implicit (if this Any type was inferred without a type annotation)
  • explicit (if this Any comes from an explicit Any in a type annotation)
  • from_unimported_type (if this Any comes from an unfollowed import)
  • from_omitted_generics (if this Any comes from an ommitted generic suchs as Any in List)
  • from_error (if this Any comes from an error)
  • special_form (if this Any is created for internal mypy purposes)

Plus, this PR contains an addition to AnyExpressionsReport to report most common "tags" of Anys (implicit, explicit, from_unimported_type, etc).

Note that I was not able to identify some of the Anys, specifically, Anys related to generators. I added a todo to each one with the following exact words(# todo: is type of this Any correct?). All of these should probably be resolved until this PR is ready to be merged.

Also, perhaps, it would be better to split the PR into two? (one would tag Anys with their provenance and the other PR would add the new kind of Any Exprs Report)

Copy link
Collaborator

@ddfisher ddfisher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a high level, I think this is a good approach. See comments for some initial feedback.

mypy/report.py Outdated
line += ('{:>{}} ' * len(widths)).format(*itertools.chain(*zip(values, widths)))
f.write(line + '\n')

def _report_any_exprs(self) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this should probably go above the previous function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

mypy/report.py Outdated
# On the following line, mypy complains about implicit generic Any and wants us to use
# typing.Counter() instead of collections.Counter().
# We cannot use typing.Counter() because it doesn't work with python 3.5 and older.
total_counter = collections.Counter() # type: ignore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, give this # type: typing.Counter[str] (or whatever the item type is, exactly).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

mypy/report.py Outdated
def __init__(self, reports: Reports, output_dir: str) -> None:
super().__init__(reports, output_dir)
self.counts = {} # type: Dict[str, Tuple[int, int]]
self.any_types_counter = {} # type: Dict[str, Any]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be precisely typed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

mypy/report.py Outdated
(TypeOfAny.special_form, "Special Form"),
(TypeOfAny.from_another_any, "From Another Any"),
]) # type: collections.OrderedDict[TypeOfAny, str]
file_column_name = "Name"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the rest of this function could be abstracted out/combined with similar looking code from the function below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I think code is much cleaner now :)

mypy/checker.py Outdated
return True
else:
gt = self.named_generic_type('typing.Generator', [AnyType(), AnyType(), AnyType()])
# todo: is type of this Any correct?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Anys don't escape the function -- special form seems right here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

try:
agt = self.named_generic_type('typing.AsyncGenerator', [AnyType(), AnyType()])
# todo: is type of this Any correct?
any_type = AnyType(TypeOfAny.special_form)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Any doesn't escape the function -- special form seems right here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

# (However, see https://github.com/python/mypy/issues/1933)
return AnyType()
# todo: is type of this Any correct?
return AnyType(TypeOfAny.special_form)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me that this should even return Any, but I think special form is fine here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

mypy/subtypes.py Outdated
else:
iter_type = AnyType()
# todo: is type of this Any correct?
iter_type = AnyType(TypeOfAny.from_error)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be special form.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that ideally this should be assert False, since all these types have one type parameter and types with incorrect type argument numbers (e.g. zero) should be "patched" in the third pass of semantic analysis. There were some efforts recently to weed out all instances with incorrect type argument count (including test fixtures), but maybe some are still there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ilevkivskyi, hmm I see. I think it's better to have a separate PR for that one. This doesn't seem to be relevant to this PR and this PR is already huge.

@ilinum
Copy link
Collaborator Author

ilinum commented Aug 3, 2017

All right, all code review feedback should be addressed now!

@ilinum ilinum changed the title [WIP] Tag Anys with their provenance Tag Anys with their provenance Aug 3, 2017
mypy/semanal.py Outdated
node = sym.node
assert isinstance(node, TypeInfo)
return Instance(node, [AnyType()] * len(node.defn.type_vars))
return Instance(node, [AnyType(TypeOfAny.implicit)] * len(node.defn.type_vars))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be special form.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

fdef.arg_kinds,
[None if argument_elide_name(n) else n for n in fdef.arg_names],
ret_type or AnyType(),
ret_type or AnyType(TypeOfAny.implicit),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this (and the other Any in this function) should be special form.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, after making this change, tests were failing, so I made them implicit again.

mypy/semanal.py Outdated
# TODO: assert len(args) == len(node.defn.type_vars)
return Instance(node, args)
return Instance(node, [AnyType()] * len(node.defn.type_vars))
return Instance(node, [AnyType(TypeOfAny.implicit)] * len(node.defn.type_vars))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thiiiink this should be special form.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Collaborator

@ddfisher ddfisher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do this.

@ddfisher
Copy link
Collaborator

ddfisher commented Aug 4, 2017

👍

@ilinum ilinum merged commit 8984321 into python:master Aug 4, 2017
@ddfisher
Copy link
Collaborator

ddfisher commented Aug 4, 2017

🎉

@ilinum ilinum deleted the tag-anys branch August 8, 2017 01:55
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

Successfully merging this pull request may close these issues.

3 participants