Skip to content

Uncertainty between submodule and local definition in new semantic analyzer #6828

Description

@ilevkivskyi

Consider this test case:

[case testNewAnalyzerImportFromTopLevelAlias]
import a.b
[file a/__init__.py]
from .b import B
from . import b as c
b = int
x: Forward
class Forward:
    ...

[file a/b.py]
class B: ...
[builtins fixtures/module.pyi]

It currently fails with Name 'c' is already defined, because on the first iteration mypy sees a.b as module, while on the second one it is a type alias. There is also a similar but different test case:

[case testNewAnalyzerImportFromTopLevelFunction]
import a.b
[file a/__init__.py]
from .b import B
from . import b as c
def b(): ...  # can be also b: int
x: Forward
class Forward:
    ...

[file a/b.py]
class B: ...
[builtins fixtures/module.pyi]

that fails with Name 'b' already defined for a similar reason. Note that we already added some special casing for a similar scenario, see #6630, to match old semantic analyzer (and also Python runtime). Setting priority to high since this causes problems with internal deployment of new analyzer. @JukkaL I assign this to you since this may be related to tracking the order of definitions.

Activity

  1. added
    bugmypy got something wrong
    false-positivemypy gave an error on correct code
    on Jun 12, 2019
  2. JukkaL commented on Jun 12, 2019

    @JukkaL
    Collaborator

    It looks like the approach taken in #6630 isn't workable and needs to be replaced with something more general. The new semantic analyzer relies on only creating a non-placeholder symbol node once per name (#6300) and submodules shouldn't deviate from this, since any deviations increase complexity and likely cause bugs.

    My current idea is that implicit submodule references shouldn't be added to symbol tables. Instead, we could look them up from a separate "module scope". If a name is defined in a module, we use that. Otherwise, we fall back to the module dictionary to check if the name refers to a module.

    To implement this logic, we'd need to keep track of where a definition is valid using the line number of the definition.

    There are various edge cases that are still unclear to me and need more thought.

  3. ilevkivskyi commented on Jun 12, 2019

    @ilevkivskyi
    MemberAuthor

    My current idea is that implicit submodule references shouldn't be added to symbol tables. Instead, we could look them up from a separate "module scope". If a name is defined in a module, we use that. Otherwise, we fall back to the module dictionary to check if the name refers to a module.

    Generally I like this idea. I was thinking about something similar, but even more global. There is another case where we want to have essentially two nodes in the same symbol table under the same name: the -redefinition thing. (Yet another will be conditional imports currently unsupported.)

    We can make a symbol table essentially a mapping from names to a deque of nodes, but __getitem__ will always return the leading one. There will be a method to access all of them. Plus two methods to push on either end, depending on whether we want to shadow existing name (like with named tuples or plugins), or not (like for redefinitions or for implicit imports).

  4. ilevkivskyi commented on Jun 12, 2019

    @ilevkivskyi
    MemberAuthor

    Yet another related thing to consider is --allow-redefinition. If we are going to move towards something more SSA-like (e.g. allowing conditional redefinitions), then the current scheme with variable renaming with primes, x, x', x'', etc., might not work well. We will need to be able to record that in

    if bool():
        x = int()
    else:
        x = str()
    foo(x)

    the last x may refer to either Var node. With the deque logic this seems possible to address.

  5. ilevkivskyi commented on Jun 17, 2019

    @ilevkivskyi
    MemberAuthor

    I think this was closed by mistake.

  6. added a commit that references this issue on Jun 18, 2019
    3e02d0f
  7. added a commit that references this issue on Jun 18, 2019
    ec60360
  8. added a commit that references this issue on Jun 18, 2019
    f68fc74
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugmypy got something wrongfalse-positivemypy gave an error on correct codepriority-0-highsemantic-analyzerProblems that happen during semantic analysis

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions