-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Infer literal types in analyze_var_ref #11340
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
base: master
Are you sure you want to change the base?
Infer literal types in analyze_var_ref #11340
Conversation
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] |
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.
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.
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.
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): |
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 about float and bytes?
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.
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) |
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.
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: |
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.
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.
Description
Partially fixes #11336.
This PR adds inferring for final types when analyzing vars.
The
last_known_valueof annotation types are set withNonecurrently, which would bring a lot of false positive when comparingInstance. I have to silence it temporally. We should check all the cases oflast_known_valueinitialization and then remove the comments in the following PRs.Test Plan
testFormatCallMatchingFinaltestFormatCallFinalChartestLiteralFineGrainedChainedViaFinalandtestLiteralFinalDirectInstanceTypesSupercedeInferredLiteral, which were wrong previously.