[red-knot] Consistent spelling of "metaclass" and "meta-type" (#16576)

## Summary

Fixes a small nit of mine -- we are currently inconsistent in our
spelling between "metaclass" and "meta class", and between "meta type"
and "meta-type". This PR means that we consistently use "metaclass" and
"meta-type".

## Test Plan

`uvx pre-commit run -a`
This commit is contained in:
Alex Waygood 2025-03-09 12:30:32 +00:00 committed by GitHub
parent 0361021863
commit 335b264fe2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 37 additions and 35 deletions

View file

@ -731,20 +731,20 @@ object first, i.e. on the metaclass:
from typing import Literal
class Meta1:
attr: Literal["meta class value"] = "meta class value"
attr: Literal["metaclass value"] = "metaclass value"
class C1(metaclass=Meta1): ...
reveal_type(C1.attr) # revealed: Literal["meta class value"]
reveal_type(C1.attr) # revealed: Literal["metaclass value"]
```
However, the meta class attribute only takes precedence over a class-level attribute if it is a data
However, the metaclass attribute only takes precedence over a class-level attribute if it is a data
descriptor. If it is a non-data descriptor or a normal attribute, the class-level attribute is used
instead (see the [descriptor protocol tests] for data/non-data descriptor attributes):
```py
class Meta2:
attr: str = "meta class value"
attr: str = "metaclass value"
class C2(metaclass=Meta2):
attr: Literal["class value"] = "class value"
@ -752,14 +752,14 @@ class C2(metaclass=Meta2):
reveal_type(C2.attr) # revealed: Literal["class value"]
```
If the class-level attribute is only partially defined, we union the meta class attribute with the
If the class-level attribute is only partially defined, we union the metaclass attribute with the
class-level attribute:
```py
def _(flag: bool):
class Meta3:
attr1 = "meta class value"
attr2: Literal["meta class value"] = "meta class value"
attr1 = "metaclass value"
attr2: Literal["metaclass value"] = "metaclass value"
class C3(metaclass=Meta3):
if flag:
@ -767,39 +767,39 @@ def _(flag: bool):
# TODO: Neither mypy nor pyright show an error here, but we could consider emitting a conflicting-declaration diagnostic here.
attr2: Literal["class value"] = "class value"
reveal_type(C3.attr1) # revealed: Unknown | Literal["meta class value", "class value"]
reveal_type(C3.attr2) # revealed: Literal["meta class value", "class value"]
reveal_type(C3.attr1) # revealed: Unknown | Literal["metaclass value", "class value"]
reveal_type(C3.attr2) # revealed: Literal["metaclass value", "class value"]
```
If the *meta class* attribute is only partially defined, we emit a `possibly-unbound-attribute`
If the *metaclass* attribute is only partially defined, we emit a `possibly-unbound-attribute`
diagnostic:
```py
def _(flag: bool):
class Meta4:
if flag:
attr1: str = "meta class value"
attr1: str = "metaclass value"
class C4(metaclass=Meta4): ...
# error: [possibly-unbound-attribute]
reveal_type(C4.attr1) # revealed: str
```
Finally, if both the meta class attribute and the class-level attribute are only partially defined,
Finally, if both the metaclass attribute and the class-level attribute are only partially defined,
we union them and emit a `possibly-unbound-attribute` diagnostic:
```py
def _(flag1: bool, flag2: bool):
class Meta5:
if flag1:
attr1 = "meta class value"
attr1 = "metaclass value"
class C5(metaclass=Meta5):
if flag2:
attr1 = "class value"
# error: [possibly-unbound-attribute]
reveal_type(C5.attr1) # revealed: Unknown | Literal["meta class value", "class value"]
reveal_type(C5.attr1) # revealed: Unknown | Literal["metaclass value", "class value"]
```
## Union of attributes

View file

@ -40,10 +40,10 @@ class Meta(type):
def __getitem__(cls, key: int) -> str:
return str(key)
class DunderOnMetaClass(metaclass=Meta):
class DunderOnMetaclass(metaclass=Meta):
pass
reveal_type(DunderOnMetaClass[0]) # revealed: str
reveal_type(DunderOnMetaclass[0]) # revealed: str
```
If the dunder method is only present on the class itself, it will not be called:

View file

@ -640,7 +640,7 @@ reveal_type(C.d) # revealed: int
## Dunder methods
Dunder methods are looked up on the meta type, but we still need to invoke the descriptor protocol:
Dunder methods are looked up on the meta-type, but we still need to invoke the descriptor protocol:
```py
class SomeCallable:

View file

@ -163,7 +163,7 @@ reveal_type(B.__class__) # revealed: Literal[M]
## Non-class
When a class has an explicit `metaclass` that is not a class, but is a callable that accepts
`type.__new__` arguments, we should return the meta type of its return type.
`type.__new__` arguments, we should return the meta-type of its return type.
```py
def f(*args, **kwargs) -> int: ...

View file

@ -383,7 +383,7 @@ static_assert(is_subtype_of(LiteralStr, type[object]))
static_assert(not is_subtype_of(type[str], LiteralStr))
# custom meta classes
# custom metaclasses
type LiteralHasCustomMetaclass = TypeOf[HasCustomMetaclass]

View file

@ -136,9 +136,9 @@ enum AttributeKind {
/// This enum is used to control the behavior of the descriptor protocol implementation.
/// When invoked on a class object, the fallback type (a class attribute) can shadow a
/// non-data descriptor of the meta type (the class's metaclass). However, this is not
/// non-data descriptor of the meta-type (the class's metaclass). However, this is not
/// true for instances. When invoked on an instance, the fallback type (an attribute on
/// the instance) can not completely shadow a non-data descriptor of the meta type (the
/// the instance) can not completely shadow a non-data descriptor of the meta-type (the
/// class), because we do not currently attempt to statically infer if an instance
/// attribute is definitely defined (i.e. to check whether a particular method has been
/// called).
@ -148,17 +148,17 @@ enum InstanceFallbackShadowsNonDataDescriptor {
No,
}
/// Dunder methods are looked up on the meta type of a type without potentially falling
/// Dunder methods are looked up on the meta-type of a type without potentially falling
/// back on attributes on the type itself. For example, when implicitly invoked on an
/// instance, dunder methods are not looked up as instance attributes. And when invoked
/// on a class, dunder methods are only looked up on the meta class, not the class itself.
/// on a class, dunder methods are only looked up on the metaclass, not the class itself.
///
/// All other attributes use the `WithInstanceFallback` policy.
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
enum MemberLookupPolicy {
/// Only look up the attribute on the meta type.
/// Only look up the attribute on the meta-type.
NoInstanceFallback,
/// Look up the attribute on the meta type, but fall back to attributes on the instance
/// Look up the attribute on the meta-type, but fall back to attributes on the instance
/// if the meta-type attribute is not found or if the meta-type attribute is not a data
/// descriptor.
WithInstanceFallback,
@ -1540,7 +1540,7 @@ impl<'db> Type<'db> {
}
}
/// Look up an attribute in the MRO of the meta type of `self`. This returns class-level attributes
/// Look up an attribute in the MRO of the meta-type of `self`. This returns class-level attributes
/// when called on an instance-like type, and metaclass attributes when called on a class-like type.
///
/// Basically corresponds to `self.to_meta_type().find_name_in_mro(name)`, except for the handling
@ -1555,7 +1555,9 @@ impl<'db> Type<'db> {
_ => self
.to_meta_type(db)
.find_name_in_mro(db, name.as_str())
.expect("was called on meta type"),
.expect(
"`Type::find_name_in_mro()` should return `Some()` when called on a meta-type",
),
}
}
@ -1652,14 +1654,14 @@ impl<'db> Type<'db> {
}
}
/// Look up `__get__` on the meta type of self, and call it with the arguments `self`, `instance`,
/// Look up `__get__` on the meta-type of self, and call it with the arguments `self`, `instance`,
/// and `owner`. `__get__` is different than other dunder methods in that it is not looked up using
/// the descriptor protocol itself.
///
/// In addition to the return type of `__get__`, this method also returns the *kind* of attribute
/// that `self` represents: (1) a data descriptor or (2) a non-data descriptor / normal attribute.
///
/// If `__get__` is not defined on the meta type, this method returns `None`.
/// If `__get__` is not defined on the meta-type, this method returns `None`.
#[salsa::tracked]
fn try_call_dunder_get(
self,
@ -1698,7 +1700,7 @@ impl<'db> Type<'db> {
}
}
/// Look up `__get__` on the meta type of `attribute`, and call it with `attribute`, `instance`,
/// Look up `__get__` on the meta-type of `attribute`, and call it with `attribute`, `instance`,
/// and `owner` as arguments. This method exists as a separate step as we need to handle unions
/// and intersections explicitly.
fn try_call_dunder_get_on_attribute(
@ -1783,7 +1785,7 @@ impl<'db> Type<'db> {
///
/// This method roughly performs the following steps:
///
/// - Look up the attribute `name` on the meta type of `self`. Call the result `meta_attr`.
/// - Look up the attribute `name` on the meta-type of `self`. Call the result `meta_attr`.
/// - Call `__get__` on the meta-type of `meta_attr`, if it exists. If the call succeeds,
/// replace `meta_attr` with the result of the call. Also check if `meta_attr` is a *data*
/// descriptor by testing if `__set__` or `__delete__` exist.
@ -1832,7 +1834,7 @@ impl<'db> Type<'db> {
}
// `meta_attr` is the return type of a data descriptor, but the attribute on the
// meta type is possibly-unbound. This means that we "fall through" to the next
// meta-type is possibly-unbound. This means that we "fall through" to the next
// stage of the descriptor protocol and union with the fallback type.
(
Symbol::Type(meta_attr_ty, Boundness::PossiblyUnbound),
@ -1873,7 +1875,7 @@ impl<'db> Type<'db> {
)
.with_qualifiers(meta_attr_qualifiers.union(fallback_qualifiers)),
// If the attribute is not found on the meta type, we simply return the fallback.
// If the attribute is not found on the meta-type, we simply return the fallback.
(Symbol::Unbound, _, fallback) => fallback.with_qualifiers(fallback_qualifiers),
}
}
@ -2736,7 +2738,7 @@ impl<'db> Type<'db> {
}
}
/// Look up a dunder method on the meta type of `self` and call it.
/// Look up a dunder method on the meta-type of `self` and call it.
///
/// Returns an `Err` if the dunder method can't be called,
/// or the given arguments are not valid.
@ -3163,7 +3165,7 @@ impl<'db> Type<'db> {
KnownClass::WrapperDescriptorType.to_class_literal(db)
}
Type::Callable(CallableType::General(_)) => {
// TODO: Get the meta type
// TODO: Get the meta-type
todo_type!(".to_meta_type() for general callable type")
}
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_literal(db),