Skip to content

Some flags are not publicly exported by symtablemodule.c #120029

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

Closed
picnixz opened this issue Jun 4, 2024 · 13 comments
Closed

Some flags are not publicly exported by symtablemodule.c #120029

picnixz opened this issue Jun 4, 2024 · 13 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@picnixz
Copy link
Member

picnixz commented Jun 4, 2024

Bug report

Bug description:

The symtablemodule.c file does not export DEF_COMP_ITER, DEF_TYPE_PARAM and DEF_COMP_CELL. Those flags seem to have been added after the original ones so they were probably missed/forgotten. Here is a MWE for DEF_TYPE_PARAM:

>>> import symtable
>>> s = symtable.symtable("class A[T]: pass", "?", "exec")
>>> s.get_children()[0].lookup('T')
<symbol 'T': LOCAL, DEF_LOCAL>

By the way, there are tests that are missing for those cases in test_symtable, so I can also add the corresponding test. I'm opening a PR now, but feel free to close it if you do not want to expose too many compiler flags (though, I fail to understand why you would do so).

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

@picnixz picnixz added the type-bug An unexpected behavior, bug, or error label Jun 4, 2024
@JelleZijlstra
Copy link
Member

Thanks! I merged your PR exposing DEF_TYPE_PARAM; that should indeed have been public.

The other two sound related to comprehension inlining; cc @carljm.

@picnixz
Copy link
Member Author

picnixz commented Jun 4, 2024

Yes, that's why I didn't touch them for now. I can easily find an example where exposing DEF_COMP_ITER can be useful (for instance, for IntelliSense so that PyCharm doesn't tell me "hey, your variable doesn't exist", but I'm not even sure it uses the symbol table) but I have no idea how to create a symbol with DEF_COMP_CELL.

@JelleZijlstra
Copy link
Member

I haven't checked the code recently but I assume it's used if there's an inner scope inside the listcomp, e.g. [(lambda: x) for x in [1]].

@picnixz
Copy link
Member Author

picnixz commented Jun 4, 2024

I see. For now, I'll wait for Carl's opinion on whether the other two flags should be exported. By the way, there are actually two flags that are exported but not imported (and thus not exposed in repr), namely DEF_FREE and DEF_FREE_CLASS. Should they be exposed as well?

@carljm
Copy link
Member

carljm commented Jun 4, 2024

My default position would be that the symtable module should accurately reflect the symbol table as seen by CPython, so I would export all of these and reflect them in the symbol repr.

@picnixz
Copy link
Member Author

picnixz commented Jun 5, 2024

By the way, what is the purpose of the DEF_FREE flag? I've only found a single usage in inline_comprehension which is:

int only_flags = comp_flags & ((1 << SCOPE_OFFSET) - 1);
...
only_flags &= ~DEF_FREE;

but AFAICT, DEF_FREE is never set so clearing its corresponding bit is a no-op. Similarly, the macros GENERATOR and GENERATOR_EXPRESSION are defined but never used, so I'm wondering whether they are actually needed.

@carljm
Copy link
Member

carljm commented Jun 6, 2024

DEF_FREE is supposed to mark a name as free in a scope. But it looks to me like you're right, it's never set; instead in analyze_name we just directly set scope to FREE for free names. A quick examination of the git history suggests to me that DEF_FREE dates back very early in Python's history, but a rewrite of the compiler 19 years ago in 3e0055f rendered it unused, but kept it around?

I'm currently investigating an issue (#119666) related to that line in inline_comprehension where we unset DEF_FREE, so I'll likely remove it in the PR to fix that issue. Or we can remove it separately. Personally it seems fine to me to just remove DEF_FREE altogether, since it's unused; keeping it around will just lead to confusion. It doesn't seem to be currently exposed in the Python symtable module. And it's defined in an internal-only header file. Curious what @JelleZijlstra thinks here.

I don't have any context on the GENERATOR and GENERATOR_EXPRESSION macros, but if they are unused, I think they could be removed.

@carljm
Copy link
Member

carljm commented Jun 6, 2024

I guess DEF_FREE is already visible in _symtable module, so it's possible someone is importing it from there. Maybe that's enough reason to keep it around, even if it's never used. Though I don't know why anyone would be importing it, since it's never set on a symbol.

@JelleZijlstra
Copy link
Member

I looked at the code too and agree DEF_FREE doesn't appear to be doing anything useful. It's publicly exposed but undocumented and has no conceivable use.

I think we can remove it in 3.14.

@picnixz
Copy link
Member Author

picnixz commented Jun 7, 2024

I have a question on that. Since removing DEF_FREE would cause a "hole" in the flags, am I allowed to change the order of the flags in such a way the USE flag is the first one?

The rationale is that the repr() of a symbol uses a very specific order (actually, it's the order in which the DEF_* constants are imported) and with USE as the very first possible flag. However, USE = 2 << 3 and DEF_GLOBAL = 1. I'd suggest changing the current order as follows:

/* current order */
#define DEF_GLOBAL 1         
#define DEF_LOCAL 2          
#define DEF_PARAM (2<<1)     
#define DEF_NONLOCAL (2<<2)  
#define USE (2<<3)           
#define DEF_FREE (2<<4)      
#define DEF_FREE_CLASS (2<<5)
#define DEF_IMPORT (2<<6)    
#define DEF_ANNOT (2<<7)     
#define DEF_COMP_ITER (2<<8) 
#define DEF_TYPE_PARAM (2<<9)
#define DEF_COMP_CELL (2<<10)

/* suggested order */
#define USE (1 << 0)
#define DEF_ANNOT (1 << 1)

#define DEF_IMPORT (1 << 2)
#define DEF_GLOBAL (1 << 3)
#define DEF_NONLOCAL (1 << 4)
#define DEF_LOCAL (1 << 5)

#define DEF_PARAM (1 << 6)     
#define DEF_TYPE_PARAM (1 << 7)

#define DEF_FREE_CLASS (1 << 8)
#define DEF_COMP_ITER (1 << 9) 
#define DEF_COMP_CELL (1 << 10)

The SCOPE_OFFSET would be changed updated since we are removing a flag and changing their order (actually, just removing it is fine, (and we would have holes), but changing the order makes some weird assertion failures, probably because there are some assumptions I haven't caught yet).

@JelleZijlstra
Copy link
Member

What is the problem with leaving a hole? I'd rather not change the values without a compelling reason.

@picnixz
Copy link
Member Author

picnixz commented Jun 7, 2024

What is the problem with leaving a hole? I'd rather not change the values without a compelling reason.

Well.. I find it a bit weird to have a hole (but I can revert that change). Actually, I took the opportunity of removing that hold to change the order of the flags (so that the USE flag is at the top and not in the middle, since we anyway construct the repr() of symbol's flags with USE at the beginning, e.g., USE|DEF_...).

I thought that it could have been a bit nicer to have flags grouped by what they are meant to represent (one specific reason is that I have the TYPE_PARAM flag way after the PARAM flag, which I find a bit weird).

If you want to, I split the PR into two, with one PR only removing the deprecated values and another making the change order?

JelleZijlstra pushed a commit that referenced this issue Jun 12, 2024
…iler's flags, add methods (#120099)

Expose :class:`symtable.Symbol` methods :meth:`~symtable.Symbol.is_free_class`,
:meth:`~symtable.Symbol.is_comp_iter` and :meth:`~symtable.Symbol.is_comp_cell`.

---------

Co-authored-by: Carl Meyer <carl@oddbird.net>
carljm added a commit that referenced this issue Jun 12, 2024
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
@picnixz
Copy link
Member Author

picnixz commented Jun 12, 2024

I think we are done with this one or is there something else to do?

@carljm carljm closed this as completed Jun 12, 2024
mrahtz pushed a commit to mrahtz/cpython that referenced this issue Jun 30, 2024
…e compiler's flags, add methods (python#120099)

Expose :class:`symtable.Symbol` methods :meth:`~symtable.Symbol.is_free_class`,
:meth:`~symtable.Symbol.is_comp_iter` and :meth:`~symtable.Symbol.is_comp_cell`.

---------

Co-authored-by: Carl Meyer <carl@oddbird.net>
mrahtz pushed a commit to mrahtz/cpython that referenced this issue Jun 30, 2024
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
…e compiler's flags, add methods (python#120099)

Expose :class:`symtable.Symbol` methods :meth:`~symtable.Symbol.is_free_class`,
:meth:`~symtable.Symbol.is_comp_iter` and :meth:`~symtable.Symbol.is_comp_cell`.

---------

Co-authored-by: Carl Meyer <carl@oddbird.net>
noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
…e compiler's flags, add methods (python#120099)

Expose :class:`symtable.Symbol` methods :meth:`~symtable.Symbol.is_free_class`,
:meth:`~symtable.Symbol.is_comp_iter` and :meth:`~symtable.Symbol.is_comp_cell`.

---------

Co-authored-by: Carl Meyer <carl@oddbird.net>
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants