Repository: Qiskit/qiskit

Issue:
Cannot create a schedule with a parameterized duration
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: commit 3c979ebdacecbbd213757a8149bddc309bfa58c0
- **Python version**: 3.8.5
- **Operating system**: Ubuntu 20.04

### What is the current behavior?

Cannot create a schedule with parameterized durations.

### Steps to reproduce the problem
The following fails
```python
from qiskit.pulse.transforms import inline_subroutines
from qiskit.circuit import Parameter
import qiskit.pulse as pulse
from qiskit.pulse import Drag, DriveChannel, Gaussian, ControlChannel, GaussianSquare

amp_cr = Parameter("amp")
amp = Parameter("amp")
d0 = DriveChannel(Parameter("ch0"))
c1 = ControlChannel(Parameter("ch0.1"))
sigma = Parameter("σ")
width = Parameter("w")
dur1 = Parameter("duration")
dur2 = Parameter("duration")

with pulse.build(name="xp") as xp:
    pulse.play(Gaussian(dur1, amp, sigma), d0)

with pulse.build(name="cr") as cr:
    with pulse.align_sequential():
            pulse.play(GaussianSquare(dur2, amp_cr, sigma, width), c1)
            pulse.call(xp)
            pulse.play(GaussianSquare(dur2, amp_cr, sigma, width), c1)
            pulse.call(xp)
```

### What is the expected behavior?

The code above should work.

### Suggested solutions

Needs to be investigated.



Discussion:

Resolving patch:
diff --git a/qiskit/pulse/builder.py b/qiskit/pulse/builder.py
--- a/qiskit/pulse/builder.py
+++ b/qiskit/pulse/builder.py
@@ -510,13 +510,27 @@ def call_subroutine(self,
                 these parameters are updated with the same assigned value.
 
         Raises:
-            PulseError: If specified parameter is not contained in the subroutine.
+            PulseError:
+                - When specified parameter is not contained in the subroutine
+                - When input subroutine is not valid data format.
         """
         if isinstance(subroutine, circuit.QuantumCircuit):
             self._compile_lazy_circuit()
             subroutine = self._compile_circuit(subroutine)
 
-        if len(subroutine.instructions) > 0:
+        empty_subroutine = True
+        if isinstance(subroutine, Schedule):
+            if len(subroutine.instructions) > 0:
+                empty_subroutine = False
+        elif isinstance(subroutine, ScheduleBlock):
+            if len(subroutine.blocks) > 0:
+                empty_subroutine = False
+        else:
+            raise exceptions.PulseError(f'Subroutine type {subroutine.__class__.__name__} is '
+                                        'not valid data format. Call QuantumCircuit, '
+                                        'Schedule, or ScheduleBlock.')
+
+        if not empty_subroutine:
             param_value_map = dict()
             for param_name, assigned_value in kw_params.items():
                 param_objs = subroutine.get_parameters(param_name)
@@ -1695,7 +1709,7 @@ def call_circuit(circ: circuit.QuantumCircuit):
     call(circ)
 
 
-def call(target: Union[circuit.QuantumCircuit, Schedule],
+def call(target: Union[circuit.QuantumCircuit, Schedule, ScheduleBlock],
          name: Optional[str] = None,
          value_dict: Optional[Dict[ParameterValueType, ParameterValueType]] = None,
          **kw_params: ParameterValueType):


Test patch:
diff --git a/test/python/pulse/test_builder.py b/test/python/pulse/test_builder.py
--- a/test/python/pulse/test_builder.py
+++ b/test/python/pulse/test_builder.py
@@ -1218,3 +1218,16 @@ def test_call_with_parameter_name_collision(self):
         self.assertEqual(play_0.pulse.sigma, 40)
         self.assertEqual(play_1.pulse.amp, 0.2)
         self.assertEqual(play_1.pulse.sigma, 40)
+
+    def test_call_subroutine_with_parametrized_duration(self):
+        """Test call subroutine containing a parametrized duration."""
+        dur = circuit.Parameter('dur')
+
+        with pulse.build() as subroutine:
+            pulse.play(pulse.Constant(dur, 0.1), pulse.DriveChannel(0))
+            pulse.play(pulse.Constant(dur, 0.2), pulse.DriveChannel(0))
+
+        with pulse.build() as main:
+            pulse.call(subroutine)
+
+        self.assertEqual(len(main.blocks), 1)