[ty] Avoid falling back to `Unknown` when collecting type context constraints (#28297)

During fixpoint iteration, we use argument types inferred from previous
iterations as type context for subsequent iterations. Arguments being
forwarded to a `ParamSpec` are initially inferred without type context,
as the type of the callable has not yet been inferred, and so we clear
their types after the initial iteration. However, we currently fallback
to `Unknown` as type context for arguments that have not yet been
inferred, even if they have been intentionally cleared, which can
pollute the types inferred in the next iteration. We should instead
avoid providing any type context in this case.

```py
from typing import TypedDict, Callable

class Payload(TypedDict):
    x: int

def forward[**P](function: Callable[P, None], /, *args: P.args, **kwargs: P.kwargs) -> None:
    function(*args, **kwargs)

def pair[T](first: T, second: T) -> None: ...
def _(payload: Payload):
    forward(pair, reveal_type({"x": 1}), payload)  # main: dict[str, int], fixed: Payload
```
diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md
index 1469056..490b68c 100644
--- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md
+++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/paramspec.md
@@ -970,6 +970,37 @@
 )
 ```
 
+This also applies when the parameter type is a bare type variable:
+
+```py
+from ty_extensions._internal import Unknown
+
+class Payload(TypedDict):
+    x: int
+
+def forward[**P](function: Callable[P, None], /, *args: P.args, **kwargs: P.kwargs) -> None:
+    function(*args, **kwargs)
+
+def pair[T](first: T, second: T) -> None: ...
+def _(payload: Payload):
+    forward(pair, reveal_type({"x": 1}), payload)  # revealed: Payload
+    forward(pair, payload, reveal_type({"x": 1}))  # revealed: Payload
+
+def triple[T](first: T, second: T, third: T) -> None: ...
+def _(payload: Payload, unknown: Unknown):
+    # TODO: This should reveal `Payload`.
+    forward(triple, reveal_type({"x": 1}), payload, unknown)  # revealed: dict[str, int]
+```
+
+We use a type-variable default as type context when the forwarded arguments do not otherwise
+constrain it:
+
+```py
+def default[T = Callable[[int], int]](callback: T) -> None: ...
+
+forward(default, lambda x: reveal_type(x))  # revealed: int
+```
+
 ### Specializing `ParamSpec` with another `ParamSpec`
 
 ```py
diff --git a/crates/ty_python_semantic/src/types/call/arguments.rs b/crates/ty_python_semantic/src/types/call/arguments.rs
index 387ebd1..5c0cb78 100644
--- a/crates/ty_python_semantic/src/types/call/arguments.rs
+++ b/crates/ty_python_semantic/src/types/call/arguments.rs
@@ -81,11 +81,19 @@
     }
 
     /// Returns the type of this argument when inferred against the provided declared type.
+    ///
+    /// If the type was not inferred against the declared type directly, this method will fall back to
+    /// [`Self::get_default`].
+    pub(crate) fn try_get_for_declared_type(&self, tcx: Type<'db>) -> Option<Type<'db>> {
+        self.types.get(&tcx).copied().or_else(|| self.get_default())
+    }
+
+    /// Returns the type of this argument when inferred against the provided declared type.
+    ///
+    /// If the type was not inferred against the declared type directly, this method will fall back to
+    /// [`Self::get_default`], or to `Unknown` if no fallback type exists.
     pub(crate) fn get_for_declared_type(&self, tcx: Type<'db>) -> Type<'db> {
-        self.types
-            .get(&tcx)
-            .copied()
-            .or_else(|| self.get_default())
+        self.try_get_for_declared_type(tcx)
             .unwrap_or(Type::unknown())
     }
 
@@ -110,7 +118,7 @@
 impl<'a, 'db> CallArguments<'a, 'db> {
     /// Create `CallArguments` from AST arguments. We will use the provided callback to obtain the
     /// type of each splatted argument, so that we can determine its length. All other arguments
-    /// will remain uninitialized as `Unknown`.
+    /// will remain uninitialized.
     pub(crate) fn from_arguments(
         arguments: &'a ast::Arguments,
         mut infer_argument_type: impl FnMut(&ast::ArgOrKeyword, &ast::Expr) -> Type<'db>,
diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs
index 0c29912..354afc1 100644
--- a/crates/ty_python_semantic/src/types/call/bind.rs
+++ b/crates/ty_python_semantic/src/types/call/bind.rs
@@ -5825,7 +5825,7 @@
                             .unwrap_or_else(|| parameter.annotated_type());
                         let argument_type = matched_parameter
                             .argument_type
-                            .unwrap_or_else(|| argument_types.get_for_declared_type(declared_type));
+                            .or_else(|| argument_types.try_get_for_declared_type(declared_type))?;
 
                         Some(ArgumentRelation::new(
                             argument_index,