Skip to content

Conversation

@97littleleaf11
Copy link
Collaborator

@97littleleaf11 97littleleaf11 commented Oct 15, 2021

Description

Partially fixes #11336.

This PR adds inferring for final types when analyzing vars.

The last_known_value of annotation types are set with None currently, which would bring a lot of false positive when comparing Instance. I have to silence it temporally. We should check all the cases of last_known_value initialization and then remove the comments in the following PRs.

Test Plan

  • Adds testFormatCallMatchingFinal
  • Fixes testFormatCallFinalChar testLiteralFineGrainedChainedViaFinal and testLiteralFinalDirectInstanceTypesSupercedeInferredLiteral, which were wrong previously.

mypy/types.py Outdated
# such a type directly into "None". So, "None" is not a valid parameter of
# LiteralType and is omitted from this list.
LiteralValue: _TypeAlias = Union[int, str, bool]
LiteralValue: _TypeAlias = Union[int, str, float, bool]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to PEP 586, which describes Literal, floats are currently not allowed as Literals:

The following are provisionally disallowed for simplicity. We can consider allowing them in future extensions of this PEP.

Floats: e.g. Literal[3.14]. Representing Literals of infinity or NaN in a clean way is tricky; real-world APIs are unlikely to vary their behavior based on a float parameter.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out!

# If `var` has final_value, we could update its type with literal type.
if var.name in {'True', 'False'}:
return self.infer_literal_expr_type(var.name == 'True', 'builtins.bool')
if isinstance(var.final_value, int) or isinstance(var.final_value, str):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about float and bytes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Literal[float] is illegal. And we actually treat bytes as str in mypy for convenience.

and self.last_known_value == other.last_known_value)
and self.args == other.args)
# TODO: last_known_value is not set correctly at initializations of Literal type
# and self.last_known_value == other.last_known_value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not safe, since now two Instance objects that compare equal can have different hash values.

Since these support hashing, it seems necessary to also use last_known_value when comparing for equality. Otherwise all sorts of weird (and hard-to-debug) things could happen.

I think that fixing the value of last_known_value could be the way to go. Alternatively, it may be feasible to replace == with comparing type and args attributes in selected contexts only (e.g. replace i1 == i2 with i1.type == i2.type and i1.args == i2.args), but I'm not sure about this.


def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Type:
def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str,
fallback_typ: Optional[Instance] = None) -> Type:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This signature is now a bit awkward. I think that it would be better to always only take an Instance, and some callers can be updated to use self.named_type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mypy does not detect redundant keyword arguments in 'str.format()'

4 participants