Repository: PrefectHQ/prefect

Issue:
Parameter must be bound before case context
## Current behavior 0.11.0
`case.__enter__` mimics python if blocks, yet assumes that parameters are bound to the flow outside its context. That can cause some head-scratching for users.
```python
from prefect import task, Parameter, Flow
from prefect.tasks.control_flow import merge, case

with Flow("test maybe first param use") as f:
    x = Parameter("x")
    p = Parameter("p")
    with case(p > 10, True):
        y = x-p
    y = merge(y, p)

state = f.run(parameters=dict(x=0, p=11))
assert state.result[y].result == -11
state = f.run(parameters=dict(x=0, p=9))
assert state.result[y].result == 9
```
**Errors** with:
```
Traceback (most recent call last):
  File "pref_case_bind.py", line 8, in <module>
    y = x-p
  File "~/miniconda3/lib/python3.6/site-packages/prefect/tasks/control_flow/case.py", line 100, in __exit__
    child.set_upstream(cond, flow=self._flow)
  File "~/miniconda3/lib/python3.6/site-packages/prefect/core/task.py", line 591, in set_upstream
    self.set_dependencies(flow=flow, upstream_tasks=[task], mapped=mapped)
  File "~/miniconda3/lib/python3.6/site-packages/prefect/core/task.py", line 566, in set_dependencies
    mapped=mapped,
  File "~/miniconda3/lib/python3.6/site-packages/prefect/core/flow.py", line 811, in set_dependencies
    mapped=is_mapped,
  File "~/miniconda3/lib/python3.6/site-packages/prefect/core/flow.py", line 482, in add_edge
    "Parameters must be root tasks and can not have upstream dependencies."
ValueError: Parameters must be root tasks and can not have upstream dependencies.
```
**Passes** if: `x = Parameter("x")()`

## Proposed behavior
If `child` is a `Parameter` we would `.bind(self_flow)` between L#99 and L#100. I cannot think of any unintended side-effects, because use outside of a case context also binds yet unbound parameters (please confirm though).

## Example
See above



Discussion:

Resolving patch:
diff --git a/src/prefect/core/flow.py b/src/prefect/core/flow.py
--- a/src/prefect/core/flow.py
+++ b/src/prefect/core/flow.py
@@ -469,9 +469,12 @@ def add_task(self, task: Task) -> Task:
             self.tasks.add(task)
             self._cache.clear()
 
-            case = prefect.context.get("case", None)
-            if case is not None:
-                case.add_task(task, self)
+            # Parameters must be root tasks
+            # All other new tasks should be added to the current case (if any)
+            if not isinstance(task, Parameter):
+                case = prefect.context.get("case", None)
+                if case is not None:
+                    case.add_task(task, self)
 
         return task
 


Test patch:
diff --git a/tests/tasks/test_control_flow.py b/tests/tasks/test_control_flow.py
--- a/tests/tasks/test_control_flow.py
+++ b/tests/tasks/test_control_flow.py
@@ -1,7 +1,7 @@
 import pytest
 
 import prefect
-from prefect import Flow, Task, task
+from prefect import Flow, Task, task, Parameter
 from prefect.engine.result import NoResult
 from prefect.engine.state import Skipped, Success
 from prefect.tasks.control_flow import FilterTask, ifelse, merge, switch, case
@@ -514,3 +514,16 @@ def test_case_imperative_api(self, branch):
         elif branch == "c":
             for t in [a, b, c, d]:
                 assert state.result[t].is_skipped()
+
+    def test_case_with_parameters(self):
+        with Flow("test") as flow:
+            x = Parameter("x")
+            cond = identity(True)
+            with case(cond, True):
+                y1 = x + 1
+            with case(cond, False):
+                y2 = x - 1
+
+        state = flow.run(x=1)
+        assert state.result[y1].result == 2
+        assert state.result[y2].is_skipped()