-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Use namespaces for function type variables #17311
Changes from 1 commit
8bdbe90
ffc982e
40f00cf
15ab29a
60601e5
2f68fd9
1693303
3dbdb3b
d506a56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,7 @@ | |
Type, | ||
TypeOfAny, | ||
TypeType, | ||
TypeVarId, | ||
TypeVarLikeType, | ||
TypeVarType, | ||
UnboundType, | ||
|
@@ -569,40 +570,46 @@ def add_field( | |
add_field(Var("__match_args__", match_args_type), is_initialized_in_class=True) | ||
|
||
assert info.tuple_type is not None # Set by update_tuple_type() above. | ||
tvd = TypeVarType( | ||
shared_self_type = TypeVarType( | ||
name=SELF_TVAR_NAME, | ||
fullname=info.fullname + "." + SELF_TVAR_NAME, | ||
fullname=f"{info.fullname}.{SELF_TVAR_NAME}", | ||
# Namespace is patched per-method below. | ||
id=self.api.tvar_scope.new_unique_func_id(), | ||
values=[], | ||
upper_bound=info.tuple_type, | ||
default=AnyType(TypeOfAny.from_omitted_generics), | ||
) | ||
selftype = tvd | ||
|
||
def add_method( | ||
funcname: str, | ||
ret: Type, | ||
ret: Type | None, # None means use (patched) self-type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realize we can't pass self_type anymore because the ids are now per method. Would it make sense to create a no-op class for this
so that the type here would be
? Given the comment here I don't think it makes that much difference to understandability of the implementation, but lifting the semantics to the type level probably makes callsites easier to read and will make things like signature help in the IDE more descriptive. |
||
args: list[Argument], | ||
is_classmethod: bool = False, | ||
is_new: bool = False, | ||
) -> None: | ||
fullname = f"{info.fullname}.{funcname}" | ||
self_type = shared_self_type.copy_modified( | ||
id=TypeVarId(shared_self_type.id.raw_id, namespace=fullname) | ||
) | ||
if ret is None: | ||
ret = self_type | ||
if is_classmethod or is_new: | ||
first = [Argument(Var("_cls"), TypeType.make_normalized(selftype), None, ARG_POS)] | ||
first = [Argument(Var("_cls"), TypeType.make_normalized(self_type), None, ARG_POS)] | ||
else: | ||
first = [Argument(Var("_self"), selftype, None, ARG_POS)] | ||
first = [Argument(Var("_self"), self_type, None, ARG_POS)] | ||
args = first + args | ||
|
||
types = [arg.type_annotation for arg in args] | ||
items = [arg.variable.name for arg in args] | ||
arg_kinds = [arg.kind for arg in args] | ||
assert None not in types | ||
signature = CallableType(cast(List[Type], types), arg_kinds, items, ret, function_type) | ||
signature.variables = [tvd] | ||
signature.variables = [self_type] | ||
func = FuncDef(funcname, args, Block([])) | ||
func.info = info | ||
func.is_class = is_classmethod | ||
func.type = set_callable_name(signature, func) | ||
func._fullname = info.fullname + "." + funcname | ||
func._fullname = fullname | ||
func.line = line | ||
if is_classmethod: | ||
v = Var(funcname, func.type) | ||
|
@@ -620,13 +627,13 @@ def add_method( | |
|
||
add_method( | ||
"_replace", | ||
ret=selftype, | ||
ret=None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (all the calls in this block are examples of where I think the code is less readable now, and making a dummy |
||
args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars], | ||
) | ||
if self.options.python_version >= (3, 13): | ||
add_method( | ||
"__replace__", | ||
ret=selftype, | ||
ret=None, | ||
args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars], | ||
) | ||
|
||
|
@@ -635,11 +642,11 @@ def make_init_arg(var: Var) -> Argument: | |
kind = ARG_POS if default is None else ARG_OPT | ||
return Argument(var, var.type, default, kind) | ||
|
||
add_method("__new__", ret=selftype, args=[make_init_arg(var) for var in vars], is_new=True) | ||
add_method("__new__", ret=None, args=[make_init_arg(var) for var in vars], is_new=True) | ||
add_method("_asdict", args=[], ret=ordereddictype) | ||
add_method( | ||
"_make", | ||
ret=selftype, | ||
ret=None, | ||
is_classmethod=True, | ||
args=[Argument(Var("iterable", iterable_type), iterable_type, None, ARG_POS)], | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the name "tvd" supposed to mean?
Glad to see it gone, the only thing I can even come up with is "type var default" but that doesn't seem like the best name for something that's only ever self type even in non-abbreviated form.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"tvd" stays for
TypeVarDef
which is not a thing since around couple years ago.