|
69 | 69 | try_expanding_sum_type_to_union, tuple_fallback, make_simplified_union,
|
70 | 70 | true_only, false_only, erase_to_union_or_bound, function_type,
|
71 | 71 | callable_type, try_getting_str_literals, custom_special_method,
|
72 |
| - is_literal_type_like, |
| 72 | + is_literal_type_like, simple_literal_type, |
73 | 73 | )
|
74 | 74 | from mypy.message_registry import ErrorMessage
|
75 | 75 | import mypy.errorcodes as codes
|
@@ -3874,26 +3874,43 @@ def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = F
|
3874 | 3874 | if_type = self.analyze_cond_branch(if_map, e.if_expr, context=ctx,
|
3875 | 3875 | allow_none_return=allow_none_return)
|
3876 | 3876 |
|
| 3877 | + # we want to keep the narrowest value of if_type for union'ing the branches |
| 3878 | + # however, it would be silly to pass a literal as a type context. Pass the |
| 3879 | + # underlying fallback type instead. |
| 3880 | + if_type_fallback = simple_literal_type(get_proper_type(if_type)) or if_type |
| 3881 | + |
3877 | 3882 | # Analyze the right branch using full type context and store the type
|
3878 | 3883 | full_context_else_type = self.analyze_cond_branch(else_map, e.else_expr, context=ctx,
|
3879 | 3884 | allow_none_return=allow_none_return)
|
| 3885 | + |
3880 | 3886 | if not mypy.checker.is_valid_inferred_type(if_type):
|
3881 | 3887 | # Analyze the right branch disregarding the left branch.
|
3882 | 3888 | else_type = full_context_else_type
|
| 3889 | + # we want to keep the narrowest value of else_type for union'ing the branches |
| 3890 | + # however, it would be silly to pass a literal as a type context. Pass the |
| 3891 | + # underlying fallback type instead. |
| 3892 | + else_type_fallback = simple_literal_type(get_proper_type(else_type)) or else_type |
3883 | 3893 |
|
3884 | 3894 | # If it would make a difference, re-analyze the left
|
3885 | 3895 | # branch using the right branch's type as context.
|
3886 |
| - if ctx is None or not is_equivalent(else_type, ctx): |
| 3896 | + if ctx is None or not is_equivalent(else_type_fallback, ctx): |
3887 | 3897 | # TODO: If it's possible that the previous analysis of
|
3888 | 3898 | # the left branch produced errors that are avoided
|
3889 | 3899 | # using this context, suppress those errors.
|
3890 |
| - if_type = self.analyze_cond_branch(if_map, e.if_expr, context=else_type, |
| 3900 | + if_type = self.analyze_cond_branch(if_map, e.if_expr, context=else_type_fallback, |
3891 | 3901 | allow_none_return=allow_none_return)
|
3892 | 3902 |
|
| 3903 | + elif if_type_fallback == ctx: |
| 3904 | + # There is no point re-running the analysis if if_type is equal to ctx. |
| 3905 | + # That would be an exact duplicate of the work we just did. |
| 3906 | + # This optimization is particularly important to avoid exponential blowup with nested |
| 3907 | + # if/else expressions: https://github.com/python/mypy/issues/9591 |
| 3908 | + # TODO: would checking for is_proper_subtype also work and cover more cases? |
| 3909 | + else_type = full_context_else_type |
3893 | 3910 | else:
|
3894 | 3911 | # Analyze the right branch in the context of the left
|
3895 | 3912 | # branch's type.
|
3896 |
| - else_type = self.analyze_cond_branch(else_map, e.else_expr, context=if_type, |
| 3913 | + else_type = self.analyze_cond_branch(else_map, e.else_expr, context=if_type_fallback, |
3897 | 3914 | allow_none_return=allow_none_return)
|
3898 | 3915 |
|
3899 | 3916 | # Only create a union type if the type context is a union, to be mostly
|
|
0 commit comments