Repository: pola-rs/polars (language: python)

Issue:
list.set_intersection operates on the wrong columns when multiple columns are selected with pl.col
### Checks

- [X] I have checked that this issue has not already been reported.
- [X] I have confirmed this bug exists on the [latest version](https://pypi.org/project/polars/) of Polars.

### Reproducible example

```python
import polars as pl

df = pl.LazyFrame({
	"a": [
		[1, 2],
		[1, 2],
	],
	"b": [
		[1, 3],
		[2, 3],
	],
	"c": [
		[1, 2],
		[1, 2],
	]
})

separate = (
	df.with_columns(pl.col("a").list.set_intersection("c"))
	.with_columns(pl.col("b").list.set_intersection("c"))
)

together = (
	df.with_columns(pl.col("a", "b").list.set_intersection("c"))
)

# Print the base dataframe
print(df.collect())

print("-" * 50)

# Print the result of performing the operations separately
print(separate)
print(separate.collect())

print("-" * 50)

# Print the result of trying to perform the operations together
print(together)
print(together.collect())
```
Output:
```
shape: (2, 3)
┌───────────┬───────────┬───────────┐
│ a         ┆ b         ┆ c         │
│ ---       ┆ ---       ┆ ---       │
│ list[i64] ┆ list[i64] ┆ list[i64] │
╞═══════════╪═══════════╪═══════════╡
│ [1, 2]    ┆ [1, 3]    ┆ [1, 2]    │
│ [1, 2]    ┆ [2, 3]    ┆ [1, 2]    │
└───────────┴───────────┴───────────┘
--------------------------------------------------
naive plan: (run LazyFrame.explain(optimized=True) to see the optimized plan)

 WITH_COLUMNS:
 [col("b").list.intersection([col("c")])]
   WITH_COLUMNS:
   [col("a").list.intersection([col("c")])]
    DF ["a", "b", "c"]; PROJECT */3 COLUMNS; SELECTION: None
shape: (2, 3)
┌───────────┬───────────┬───────────┐
│ a         ┆ b         ┆ c         │
│ ---       ┆ ---       ┆ ---       │
│ list[i64] ┆ list[i64] ┆ list[i64] │
╞═══════════╪═══════════╪═══════════╡
│ [1, 2]    ┆ [1]       ┆ [1, 2]    │
│ [1, 2]    ┆ [2]       ┆ [1, 2]    │
└───────────┴───────────┴───────────┘
--------------------------------------------------
naive plan: (run LazyFrame.explain(optimized=True) to see the optimized plan)

 WITH_COLUMNS:
 [col("a").list.intersection([col("b"), col("c")])]
  DF ["a", "b", "c"]; PROJECT */3 COLUMNS; SELECTION: None
shape: (2, 3)
┌───────────┬───────────┬───────────┐
│ a         ┆ b         ┆ c         │
│ ---       ┆ ---       ┆ ---       │
│ list[i64] ┆ list[i64] ┆ list[i64] │
╞═══════════╪═══════════╪═══════════╡
│ [1]       ┆ [1, 3]    ┆ [1, 2]    │
│ [2]       ┆ [2, 3]    ┆ [1, 2]    │
└───────────┴───────────┴───────────┘
```

### Log output

_No response_

### Issue description

I am trying to replace `a` with `a ^ c` and replace `b` with `b ^ c`. If I perform these two operations separately, it works. However, if I try to use `pl.col` to select both `a` and `b` and perform both operations at the same time, instead `a` is replaced with `a ^ b ^ c` and nothing happens to `b`.

### Expected behavior

When I use `pl.col` to select both `a` and `b` and perform on each the set interaction with `c`, it should behave the same as when I compute the two intersections separately.

### Installed versions

<details>

```
--------Version info---------
Polars:              1.7.1
Index type:          UInt32
Platform:            Linux-6.10.9-artix1-2-x86_64-with-glibc2.40
Python:              3.11.5 (main, Oct 18 2023, 09:37:15) [GCC 13.2.1 20230801]

----Optional dependencies----
adbc_driver_manager  <not installed>
altair               5.1.2
cloudpickle          <not installed>
connectorx           <not installed>
deltalake            <not installed>
fastexcel            <not installed>
fsspec               <not installed>
gevent               <not installed>
great_tables         <not installed>
matplotlib           3.8.0
nest_asyncio         1.5.8
numpy                1.26.1
openpyxl             3.1.2
pandas               2.1.1
pyarrow              16.0.0
pydantic             <not installed>
pyiceberg            <not installed>
sqlalchemy           <not installed>
torch                <not installed>
xlsx2csv             <not installed>
xlsxwriter           <not installed>
```

</details>



Discussion / hints:
Can reproduce.

It may be easier to see the bug using `select` - as `b` disappears.

```python
df.select(pl.col("a", "b").list.set_intersection("c")).collect()
# shape: (2, 1)
# ┌───────────┐
# │ a         │
# │ ---       │
# │ list[i64] │
# ╞═══════════╡
# │ [1]       │
# │ [2]       │
# └───────────┘
```

It also happens for DataFrames, so doesn't appear to be an optimizer issue.

Fix patch:
diff --git a/crates/polars-plan/src/dsl/array.rs b/crates/polars-plan/src/dsl/array.rs
index 23faf363421c..65bb0bb53e15 100644
--- a/crates/polars-plan/src/dsl/array.rs
+++ b/crates/polars-plan/src/dsl/array.rs
@@ -144,17 +144,12 @@ impl ArrayNameSpace {
     pub fn count_matches<E: Into<Expr>>(self, element: E) -> Expr {
         let other = element.into();
 
-        self.0
-            .map_many_private(
-                FunctionExpr::ArrayExpr(ArrayFunction::CountMatches),
-                &[other],
-                false,
-                None,
-            )
-            .with_function_options(|mut options| {
-                options.flags |= FunctionFlags::INPUT_WILDCARD_EXPANSION;
-                options
-            })
+        self.0.map_many_private(
+            FunctionExpr::ArrayExpr(ArrayFunction::CountMatches),
+            &[other],
+            false,
+            None,
+        )
     }
 
     #[cfg(feature = "array_to_struct")]
diff --git a/crates/polars-plan/src/dsl/functions/temporal.rs b/crates/polars-plan/src/dsl/functions/temporal.rs
index 9a18abda55fd..eb9ead1e9974 100644
--- a/crates/polars-plan/src/dsl/functions/temporal.rs
+++ b/crates/polars-plan/src/dsl/functions/temporal.rs
@@ -217,9 +217,7 @@ pub fn datetime(args: DatetimeArgs) -> Expr {
             }),
             options: FunctionOptions {
                 collect_groups: ApplyOptions::ElementWise,
-                flags: FunctionFlags::default()
-                    | FunctionFlags::INPUT_WILDCARD_EXPANSION
-                    | FunctionFlags::ALLOW_RENAME,
+                flags: FunctionFlags::default() | FunctionFlags::ALLOW_RENAME,
                 fmt_str: "datetime",
                 ..Default::default()
             },
diff --git a/crates/polars-plan/src/dsl/list.rs b/crates/polars-plan/src/dsl/list.rs
index 3a1a37c9f393..83b30b021f25 100644
--- a/crates/polars-plan/src/dsl/list.rs
+++ b/crates/polars-plan/src/dsl/list.rs
@@ -318,8 +318,7 @@ impl ListNameSpace {
                 cast_to_supertypes: Some(SuperTypeOptions {
                     flags: SuperTypeFlags::default() | SuperTypeFlags::ALLOW_IMPLODE_LIST,
                 }),
-                flags: FunctionFlags::default()
-                    | FunctionFlags::INPUT_WILDCARD_EXPANSION & !FunctionFlags::RETURNS_SCALAR,
+                flags: FunctionFlags::default() & !FunctionFlags::RETURNS_SCALAR,
                 ..Default::default()
             },
         }


Test patch:
diff --git a/py-polars/tests/unit/functions/as_datatype/test_datetime.py b/py-polars/tests/unit/functions/as_datatype/test_datetime.py
index 62cc5fe09ff0..7dce89471cfb 100644
--- a/py-polars/tests/unit/functions/as_datatype/test_datetime.py
+++ b/py-polars/tests/unit/functions/as_datatype/test_datetime.py
@@ -71,3 +71,13 @@ def test_datetime_ambiguous_time_zone_earliest() -> None:
     expected = datetime(2018, 10, 28, 2, 30, tzinfo=ZoneInfo("Europe/Brussels"))
     assert result == expected
     assert result.fold == 0
+
+
+def test_datetime_wildcard_expansion() -> None:
+    df = pl.DataFrame({"a": [1], "b": [2]})
+    assert df.select(
+        pl.datetime(year=pl.all(), month=pl.all(), day=pl.all()).name.keep()
+    ).to_dict(as_series=False) == {
+        "a": [datetime(1, 1, 1, 0, 0)],
+        "b": [datetime(2, 2, 2, 0, 0)],
+    }
diff --git a/py-polars/tests/unit/operations/namespaces/array/test_array.py b/py-polars/tests/unit/operations/namespaces/array/test_array.py
index 78948406578a..ea77cd0b41ee 100644
--- a/py-polars/tests/unit/operations/namespaces/array/test_array.py
+++ b/py-polars/tests/unit/operations/namespaces/array/test_array.py
@@ -393,6 +393,17 @@ def test_array_count_matches(
     assert out.to_dict(as_series=False) == {"count_matches": expected}
 
 
+def test_array_count_matches_wildcard_expansion() -> None:
+    df = pl.DataFrame(
+        {"a": [[1, 2]], "b": [[3, 4]]},
+        schema={"a": pl.Array(pl.Int64, 2), "b": pl.Array(pl.Int64, 2)},
+    )
+    assert df.select(pl.all().arr.count_matches(3)).to_dict(as_series=False) == {
+        "a": [0],
+        "b": [1],
+    }
+
+
 def test_array_to_struct() -> None:
     df = pl.DataFrame(
         {"a": [[1, 2, 3], [4, 5, None]]}, schema={"a": pl.Array(pl.Int8, 3)}
diff --git a/py-polars/tests/unit/operations/namespaces/list/test_set_operations.py b/py-polars/tests/unit/operations/namespaces/list/test_set_operations.py
index ba451dcb1e41..67b91f149d69 100644
--- a/py-polars/tests/unit/operations/namespaces/list/test_set_operations.py
+++ b/py-polars/tests/unit/operations/namespaces/list/test_set_operations.py
@@ -40,7 +40,11 @@ def test_list_set_operations_float() -> None:
 
 def test_list_set_operations() -> None:
     df = pl.DataFrame(
-        {"a": [[1, 2, 3], [1, 1, 1], [4]], "b": [[4, 2, 1], [2, 1, 12], [4]]}
+        {
+            "a": [[1, 2, 3], [1, 1, 1], [4]],
+            "b": [[4, 2, 1], [2, 1, 12], [4]],
+            "c": [[1, 2], [2, 1, 76], [8, 9]],
+        }
     )
 
     assert df.select(pl.col("a").list.set_union("b"))["a"].to_list() == [
@@ -64,6 +68,24 @@ def test_list_set_operations() -> None:
         [],
     ]
 
+    # check expansion of columns
+    assert df.select(pl.col("a", "b").list.set_intersection("c")).to_dict(
+        as_series=False
+    ) == {"a": [[1, 2], [1], []], "b": [[2, 1], [2, 1], []]}
+
+    assert df.select(pl.col("a", "b").list.set_union("c")).to_dict(as_series=False) == {
+        "a": [[1, 2, 3], [1, 2, 76], [4, 8, 9]],
+        "b": [[4, 2, 1], [2, 1, 12, 76], [4, 8, 9]],
+    }
+
+    assert df.select(pl.col("a", "b").list.set_difference("c")).to_dict(
+        as_series=False
+    ) == {"a": [[3], [], [4]], "b": [[4], [12], [4]]}
+
+    assert df.select(pl.col("a", "b").list.set_symmetric_difference("c")).to_dict(
+        as_series=False
+    ) == {"a": [[3], [2, 76], [4, 8, 9]], "b": [[4], [12, 76], [4, 8, 9]]}
+
     # check logical types
     dtype = pl.List(pl.Date)
     assert (