Repository: deepset-ai/haystack

Issue:
Remove explicit mention of Haystack "2.x" in cookbooks

Discussion:

Solution patch:
diff --git a/README.md b/README.md
index 51952278..e1855b41 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 <div align="center">
-  <a href="https://haystack.deepset.ai/"><img src="https://raw.githubusercontent.com/deepset-ai/haystack/main/docs/img/banner_20.png" alt="Green logo of a stylized white 'H' with the text 'Haystack, by deepset. Haystack 2.0 is live 🎉' Abstract green and yellow diagrams in the background."></a>
+  <a href="https://haystack.deepset.ai/"><img src="https://raw.githubusercontent.com/deepset-ai/haystack/main/docs/img/banner.png" alt="Green logo of a stylized white 'H' with the text 'Haystack, by deepset.' Abstract green and yellow diagrams in the background."></a>
 
 |         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
 | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
diff --git a/haystack/core/type_utils.py b/haystack/core/type_utils.py
index 4b84c74d..162fcc75 100644
--- a/haystack/core/type_utils.py
+++ b/haystack/core/type_utils.py
@@ -64,6 +64,12 @@ def _strict_types_are_compatible(sender, receiver):  # pylint: disable=too-many-
     # Compare generic type arguments
     sender_args = get_args(sender)
     receiver_args = get_args(receiver)
+
+    # Handle bare types
+    if not sender_args and sender_origin:
+        sender_args = (Any,)
+    if not receiver_args and receiver_origin:
+        receiver_args = (Any,) * (len(sender_args) if sender_args else 1)
     if len(sender_args) > len(receiver_args):
         return False
 
diff --git a/releasenotes/notes/add-bare-type-validation-a4720bc66ccaf5ef.yaml b/releasenotes/notes/add-bare-type-validation-a4720bc66ccaf5ef.yaml
new file mode 100644
index 00000000..0fa8f21a
--- /dev/null
+++ b/releasenotes/notes/add-bare-type-validation-a4720bc66ccaf5ef.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Treat bare types (e.g., List, Dict) as generic types with Any arguments during type compatibility checks.


Test patch:
diff --git a/test/core/pipeline/test_type_utils.py b/test/core/pipeline/test_type_utils.py
index 89e0f021..9151b277 100644
--- a/test/core/pipeline/test_type_utils.py
+++ b/test/core/pipeline/test_type_utils.py
@@ -354,13 +354,87 @@ def test_partially_overlapping_unions_are_not_compatible_strict(sender_type, rec
     assert not _types_are_compatible(sender_type, receiver_type)
 
 
+@pytest.mark.parametrize(
+    "sender_type,receiver_type", [pytest.param((List[int]), list, id="list-of-primitive-to-list-object")]
+)
+def test_list_of_primitive_to_list(sender_type, receiver_type):
+    """This currently doesn't work because we don't handle primitive types."""
+    assert not _types_are_compatible(sender_type, receiver_type)
+
+
 @pytest.mark.parametrize(
     "sender_type,receiver_type",
     [
-        pytest.param((List[int]), List, id="list-of-primitive-to-bare-list"),
-        pytest.param((List[int]), list, id="list-of-primitive-to-list-object"),
+        pytest.param(List[int], List, id="list-of-primitive-to-bare-list"),
+        pytest.param(Dict[str, int], Dict, id="dict-of-primitive-to-bare-dict"),
+        pytest.param(Set[float], Set, id="set-of-primitive-to-bare-set"),
+        pytest.param(Tuple[int, str], Tuple, id="tuple-of-primitive-to-bare-tuple"),
     ],
 )
-def test_list_of_primitive_to_list(sender_type, receiver_type):
-    """This currently doesn't work because we don't handle bare types without arguments."""
+def test_container_of_primitive_to_bare_container_strict(sender_type, receiver_type):
+    assert _types_are_compatible(sender_type, receiver_type)
+    # Bare container types should not be compatible with their typed counterparts
+    assert not _types_are_compatible(receiver_type, sender_type)
+
+
+@pytest.mark.parametrize(
+    "sender_type,receiver_type",
+    [
+        pytest.param(List[Any], List, id="list-of-any-to-bare-list"),
+        pytest.param(Dict[Any, Any], Dict, id="dict-of-any-to-bare-dict"),
+        pytest.param(Set[Any], Set, id="set-of-any-to-bare-set"),
+        pytest.param(Tuple[Any], Tuple, id="tuple-of-any-to-bare-tuple"),
+    ],
+)
+def test_container_of_any_to_bare_container_strict(sender_type, receiver_type):
+    # Both are compatible
+    assert _types_are_compatible(sender_type, receiver_type)
+    assert _types_are_compatible(receiver_type, sender_type)
+
+
+@pytest.mark.parametrize(
+    "sender_type,receiver_type",
+    [
+        pytest.param(Literal["test"], Literal, id="literal-to-bare-literal"),
+        pytest.param(Union[str, int], Union, id="union-to-bare-union"),
+        pytest.param(Optional[str], Optional, id="optional-to-bare-optional"),
+    ],
+)
+def test_always_incompatible_bare_types(sender_type, receiver_type):
+    # Neither are compatible
     assert not _types_are_compatible(sender_type, receiver_type)
+    assert not _types_are_compatible(receiver_type, sender_type)
+
+
+@pytest.mark.parametrize(
+    "sender_type,receiver_type",
+    [
+        # Nested Lists
+        pytest.param(List[List[int]], List[List], id="nested-list-to-partially-bare-list"),
+        pytest.param(List[List[int]], List, id="nested-list-to-bare-list"),
+        # Nested Dicts
+        pytest.param(Dict[str, Dict[str, int]], Dict[str, Dict], id="nested-dict-to-partially-bare-dict"),
+        pytest.param(Dict[str, Dict[str, int]], Dict, id="nested-dict-to-bare-dict"),
+        # Nested Sets
+        pytest.param(Set[Set[int]], Set[Set], id="nested-set-to-partially-bare-set"),
+        pytest.param(Set[Set[int]], Set, id="nested-set-to-bare-set"),
+        # Nested Tuples
+        pytest.param(Tuple[Tuple[int, str], bool], Tuple[Tuple, bool], id="nested-tuple-to-partially-bare-tuple"),
+        pytest.param(Tuple[Tuple[int, str], bool], Tuple, id="nested-tuple-to-bare-tuple"),
+        # Mixed nesting
+        pytest.param(List[Dict[str, int]], List[Dict], id="list-of-dict-to-list-of-bare-dict"),
+        pytest.param(Dict[str, List[int]], Dict[str, List], id="dict-with-list-to-dict-with-bare-list"),
+        pytest.param(Set[Tuple[int, str]], Set[Tuple], id="set-of-tuple-to-set-of-bare-tuple"),
+        pytest.param(
+            Tuple[List[int], Dict[str, bool]], Tuple[List, Dict], id="tuple-of-containers-to-tuple-of-bare-containers"
+        ),
+        # Triple nesting
+        pytest.param(List[List[List[int]]], List[List[List]], id="triple-nested-list-to-partially-bare"),
+        pytest.param(List[List[List[int]]], List[List], id="triple-nested-list-to-double-bare"),
+        pytest.param(List[List[List[int]]], List, id="triple-nested-list-to-completely-bare"),
+    ],
+)
+def test_nested_container_compatibility(sender_type, receiver_type):
+    assert _types_are_compatible(sender_type, receiver_type)
+    # Bare container types should not be compatible with their typed counterparts
+    assert not _types_are_compatible(receiver_type, sender_type)