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

Catch TypeVisitor subclasses with unimplemented abstract methods #730

Closed
JamesGuthrie opened this issue Jul 27, 2015 · 7 comments · Fixed by #7312
Closed

Catch TypeVisitor subclasses with unimplemented abstract methods #730

JamesGuthrie opened this issue Jul 27, 2015 · 7 comments · Fixed by #7312
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal

Comments

@JamesGuthrie
Copy link
Contributor

Issue #638 was a pain to find because the root cause is an unimplemented abstract method which silently returns None and somewhere down the line causes type checking to fail. It would be better to check this explicitly. The following shows that this is done for one of the abstract methods:
https://github.com/JukkaL/mypy/blob/bbb2dd4f07f995a4b28b8044fa91aa97960fe192/mypy/types.py#L532. There are two potential solutions: 1) use abc's @AbstractMethod decorator, 2) raise an error directly in TypeVisitor.

  1. Ensures that future implementations and changes catch subclasses which do not implement the abstract methods, but requires adding implementations for all of the abstract methods to existing subclasses which are missing them. As there are a few, it would probably be simplest to raise an error there instead of providing the complete implementation, which raises the question: why not just use 2) straight off the bat?

@JukkaL Do you have a preferred solution?

@o11c
Copy link
Contributor

o11c commented Jul 27, 2015

I am suspicious of any visitors that can meaningfully work without full implementations.

Perhaps there is a need for more specific visitors?

@JamesGuthrie
Copy link
Contributor Author

It appears as though there is a common pattern of unimplemented abstract methods (visit_star_type, visit_overloaded, visit_error_type, visit_erased_type), I figured that maybe they had been added after the initial implementation of all visitors, and don't appear in the test cases and as such haven't been caught. In total there are about 25 subclasses which do not implement all abstract methods, mostly it is either visit_star_type or visit_overloaded which are unimplemented.

@JukkaL JukkaL added the bug mypy got something wrong label Aug 4, 2015
@JukkaL
Copy link
Collaborator

JukkaL commented Aug 4, 2015

The current implementation is just sloppy, and is inherited from early pre-mypy days when there were no abstract methods.

Using @abstractmethod is probably the best option, as missing implementations can then be caught statically. Trying to catch all of these errors using test cases is an uphill battle.

JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 4, 2015
Use the @AbstractMethod decorator on abstract methods. Part of python#730
@JamesGuthrie
Copy link
Contributor Author

I've opened a PR to get the ball rolling.

As mentioned in the PR, Subclasses with incomplete implementations are:

EraseTypeVisitor (mypy/erasetype.py: 26)
    visit_ellipsis_type()
    visit_star_type()

SameTypeVisitor(mypy/sametype.py: 29)
    visit_overloaded()
    visit_ellipsis_type()
    visit_star_type()

ExpandTypeVisitor(mypy/expandtype.py: 35)
    visit_ellipsis_type()
    visit_star_type()

SubtypeVisitor(mypy/subtypes.py: 44)
    visit_ellipsis_type()
    visit_star_type()

TypeAnalyser(mypy/typeanal.py: 58)
    visit_error_type()
    visit_overloaded()
    visit_ellipsis_type()
    visit_star_type()

TypeJoinVisitor(mypy/join.py: 70)
    visit_overloaded()
    visit_ellipsis_type()
    visit_star_type()

TypeMeetVisitor(mypy/meet.py: 77)
    visit_ellipsis_type()
    visit_star_type()

ConstraintBuilderVisitor(mypy/constraints.py: 125)
    visit_error_type()
    visit_overloaded()
    visit_ellipsis_type()
    visit_star_type()
    visit_type_list()

TypeQuery(mypy/types.py: 760)
    visit_overloaded()
    visit_ellipsis_type()

subclasses of TypeQuery:
    HasAnyQuery(mypy/stats.py: 223)
    HasAnyQuery2(mypy/stats.py: 241)
    ArgInferSecondpassQuery(mypy/checkexpr.py: 1375)
    HasTypeVarQuery(mypy/checkexpr.py: 1389)
    HasErasedComponentsQuery(mypy/checkexpr.py: 1402)

TypeAnalyserPass3(mypy/typeanal.py: 234)
    visit_error_type()
    visit_overloaded()
    visit_ellipsis_type()
    visit_star_type()
    visit_type_list()

JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
Use the @AbstractMethod decorator on abstract methods which are
implemented in all subtypes. Part of python#730
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
This helps to point out the offending unimplemented abstract methods in
subtypes. Part of python#730.
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
Use the @AbstractMethod decorator on abstract methods which are
implemented in all subtypes. Part of python#730
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
This helps to point out the offending unimplemented abstract methods in
subtypes. Part of python#730.
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
JamesGuthrie added a commit to JamesGuthrie/mypy that referenced this issue Aug 24, 2015
@JamesGuthrie
Copy link
Contributor Author

Actually I rethought this, while it makes sense to move towards using the @abstractmethod annotation on all abstract methods, forcing it now means that it will have to wait until all subclasses have all necessary abstract methods implemented, which may take a while, and doesn't add any benefit until then.

I have restructured my original PR #733 with @abstractmethod annotations only on methods which are implemented in all subtypes. Additionally I added NotImplementedErrors to the remaining abstract methods so that any possible errors caused by missing implementations are made evident.

The NotImplementedErrors caused a number of tests to fail, so I provided implementations as best I could. The tests now all pass, but I'm not sure that the implementations are completely correct, so I would appreciate any feedback you can provide.

It would also be cool to add tests which fail when all currently subtypes implement each of the abstract methods, these would indicate that the @abstractmethod annotation can be added in the abstract base class. Is there an existing appropriate file to put these in, or should I add one?

JukkaL pushed a commit that referenced this issue Oct 17, 2015
Use the @AbstractMethod decorator on abstract methods which are
implemented in all subtypes. Part of #730
JukkaL pushed a commit that referenced this issue Oct 17, 2015
This helps to point out the offending unimplemented abstract methods in
subtypes. Part of #730.
JukkaL pushed a commit that referenced this issue Oct 17, 2015
JukkaL pushed a commit that referenced this issue Oct 17, 2015
JukkaL pushed a commit that referenced this issue Oct 17, 2015
JukkaL pushed a commit that referenced this issue Oct 17, 2015
sixolet added a commit to sixolet/mypy that referenced this issue Apr 20, 2017
…c" types

This is a nearly-complete fix to python#730 --
the trick is that some types aren't real, they're synthetic AST constructs, and
so we shouldn't have to deal with those in every type visitor. Only the type
visitors that deal with types before the synthetic constructs are analyzed away.
JukkaL pushed a commit that referenced this issue Apr 20, 2017
…c" types (#3204)

* Use inheritance to allow most TypeVisitors not to deal with "synthetic" types

This is a nearly-complete fix to #730 --
the trick is that some types aren't real, they're synthetic AST constructs, and
so we shouldn't have to deal with those in every type visitor. Only the type
visitors that deal with types before the synthetic constructs are analyzed away.
@jbsiddall
Copy link

Is there any update on this? mypy 0.580 is stil showing this error for code: for item in {int}: pass

@JelleZijlstra
Copy link
Member

Are you sure you're on the right issue? This one is talking about an internal problem in mypy as far as I can tell.

@JukkaL JukkaL added priority-1-normal false-positive mypy gave an error on correct code labels May 17, 2018
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Aug 10, 2019
This pull request resolves python#730 --
it makes all TypeVisitor and SyntheticTypeVisitor methods abstract.

This thankfully required fairly minimal changes. I ended up needing to
make only three non-trivial changes:

1. The visitor for PlaceholderType was moved out of TypeVisitor
   into SyntheticTypeVisitor. My understanding is that PlaceholderType
   is a semantic analysis only type, so this ought to be safe.

2. As a consequence of 1, I ended up removing the existing
   PlaceholderType visitor method from TypeTranslator. (It seems
   that method was added about 6 months ago when PlaceholderType
   was first introduced, and was untouched since then).

3. TypeIndirectionVisitor was turned from a SyntheticTypeVisitor
   into a TypeVisitor. I believe we call this visitor only in the
   final pass, after the type-checking phase.
ilevkivskyi pushed a commit that referenced this issue Aug 22, 2019
)

This pull request almost resolves #730 -- it makes all TypeVisitor and SyntheticTypeVisitor methods with the exception of TypeAliasType abstract.

This thankfully required fairly minimal changes. I ended up needing to make only three non-trivial changes:

1. The visitor for PlaceholderType was moved out of TypeVisitor into SyntheticTypeVisitor. My understanding is that PlaceholderType is a semantic analysis only type, so this ought to be safe.

2. As a consequence of 1, I ended up removing the existing PlaceholderType visitor method from TypeTranslator. (It seems that method was added about 6 months ago when PlaceholderType was first introduced, and was untouched since then).

3. TypeIndirectionVisitor was turned from a SyntheticTypeVisitor into a TypeVisitor. I believe we call this visitor only in the final pass, after the type-checking phase.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Aug 25, 2019
…thon#7312)

This pull request almost resolves python#730 -- it makes all TypeVisitor and SyntheticTypeVisitor methods with the exception of TypeAliasType abstract.

This thankfully required fairly minimal changes. I ended up needing to make only three non-trivial changes:

1. The visitor for PlaceholderType was moved out of TypeVisitor into SyntheticTypeVisitor. My understanding is that PlaceholderType is a semantic analysis only type, so this ought to be safe.

2. As a consequence of 1, I ended up removing the existing PlaceholderType visitor method from TypeTranslator. (It seems that method was added about 6 months ago when PlaceholderType was first introduced, and was untouched since then).

3. TypeIndirectionVisitor was turned from a SyntheticTypeVisitor into a TypeVisitor. I believe we call this visitor only in the final pass, after the type-checking phase.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants