diff --git a/jedi/inference/syntax_tree.py b/jedi/inference/syntax_tree.py index f55ab56b..1d8b4e2e 100644 --- a/jedi/inference/syntax_tree.py +++ b/jedi/inference/syntax_tree.py @@ -2,6 +2,7 @@ Functions inferring the syntax tree. """ import copy +import itertools from parso.python import tree @@ -515,10 +516,20 @@ def _literals_to_types(inference_state, result): def _infer_comparison(context, left_values, operator, right_values): state = context.inference_state + if isinstance(operator, str): + operator_str = operator + else: + operator_str = str(operator.value) if not left_values or not right_values: # illegal slices e.g. cause left/right_result to be None result = (left_values or NO_VALUES) | (right_values or NO_VALUES) return _literals_to_types(state, result) + elif operator_str == "|" and all( + value.is_class() or value.is_compiled() + for value in itertools.chain(left_values, right_values) + ): + # ^^^ A naive hack for PEP 604 + return ValueSet.from_sets((left_values, right_values)) else: # I don't think there's a reasonable chance that a string # operation is still correct, once we pass something like six diff --git a/test/completion/pep0604.py b/test/completion/pep0604.py new file mode 100644 index 00000000..d876e8fa --- /dev/null +++ b/test/completion/pep0604.py @@ -0,0 +1,46 @@ +from pep0484_generic_parameters import list_t_to_list_t + +list_of_ints_and_strs: list[int | str] + +# Test that unions are handled +x2 = list_t_to_list_t(list_of_ints_and_strs)[0] +#? int() str() +x2 + +for z in list_t_to_list_t(list_of_ints_and_strs): + #? int() str() + z + + +from pep0484_generic_passthroughs import ( + typed_variadic_tuple_generic_passthrough, +) + +variadic_tuple_str_int: tuple[int | str, ...] + +for m in typed_variadic_tuple_generic_passthrough(variadic_tuple_str_int): + #? str() int() + m + + +def func_returns_byteslike() -> bytes | bytearray: + pass + +#? bytes() bytearray() +func_returns_byteslike() + + +pep604_optional_1: int | str | None +pep604_optional_2: None | bytes + +#? int() str() None +pep604_optional_1 + +#? None bytes() +pep604_optional_2 + + +pep604_in_str: "int | bytes" + +#? int() bytes() +pep604_in_str