Repository: microsoft/qsharp
Pull request #1347 (2024-04-01 22:18:27)

Initial integration of RCA, preview QIR gen, and adaptive profile
In order to support adaptive profile selection in VS we have to add `Adaptive` as a compilation attribute in the std lib. This is a workaround until we design a full solution to address #996. This PR adds adaptive as a profile.

Functionality to enable adaptive profile VSCode is hidden behind a config value, as is using the preview QIR code generation from VSCode.

QIR generation for Adaptive/Unrestricted from Python will continue to raise exceptions.

Adaptive is a profile allowed in the Python APIs, but warnings will be issued to users indicating that this functionality is in preview.

The language service will surface RCA errors in VSCode and Python, but not the Notebooks (will be handled in a follow up PR).
Other integration features are being tracked in #1294 and this PR is not expected to have all functionality enabled.

github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 73d65cf0eb0aecd3dc7cfb4a78ed68bee3715469

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 73d65cf
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 354.7±1.43µs | **343.7±3.00µs** | **-3.10%** |
| Array literal evaluation | 192.4±1.26µs | **173.7±1.65µs** | **-9.72%** |
| Array update evaluation | 436.9±3.18µs | **424.8±2.13µs** | **-2.77%** |
| Core + Standard library compilation | 16.8±0.13ms | 16.9±0.37ms | +0.60% |
| Deutsch-Jozsa evaluation | 5.2±0.08ms | **5.1±0.04ms** | **-1.92%** |
| Large file parity evaluation | 33.8±0.08ms | **33.6±0.59ms** | **-0.59%** |
| Large input file compilation | 11.3±0.09ms | **11.2±0.11ms** | **-0.88%** |
| Large input file compilation (interpreter) | 44.6±1.23ms | 43.8±1.12ms | -1.79% |
| Large nested iteration | 34.9±0.29ms | **33.7±0.45ms** | **-3.44%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1490.3±28.67µs | 1499.3±44.35µs | +0.60% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.7±0.07ms | **7.6±0.09ms** | **-1.30%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1404.4±27.45µs | 1411.2±32.85µs | +0.48% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.1±0.16ms | 21.2±0.17ms | +0.47% |
| Teleport evaluation | 83.5±3.61µs | 82.2±3.61µs | -1.56% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 0e830af21c438a118902981fa4df3b70bccb5cb5

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 0e830af
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 355.1±2.97µs | **345.2±2.99µs** | **-2.79%** |
| Array literal evaluation | 198.1±5.07µs | **182.9±3.46µs** | **-7.67%** |
| Array update evaluation | 437.8±4.37µs | **427.8±2.77µs** | **-2.28%** |
| Core + Standard library compilation | 17.5±0.88ms | 17.7±0.73ms | +1.14% |
| Deutsch-Jozsa evaluation | 5.2±0.12ms | 5.2±0.43ms | 0.00% |
| Large file parity evaluation | **33.8±0.12ms** | 34.0±0.19ms | **+0.59%** |
| Large input file compilation | 11.7±0.25ms | 11.8±0.36ms | +0.85% |
| Large input file compilation (interpreter) | 48.8±1.84ms | 48.3±1.53ms | -1.02% |
| Large nested iteration | 34.5±0.40ms | **33.5±0.22ms** | **-2.90%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1506.2±41.09µs | 1498.1±46.45µs | -0.54% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.9±0.16ms | 7.8±0.12ms | -1.27% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1438.6±57.78µs | 1408.7±44.37µs | -2.08% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | **21.4±0.26ms** | 21.7±0.33ms | **+1.40%** |
| Teleport evaluation | 83.1±4.01µs | 83.7±3.77µs | +0.72% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 85844aa0d22c65915ef952ccc1b25bb5be1b980e

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for f33f647
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 350.1±1.26µs | 350.1±21.52µs | 0.00% |
| Array literal evaluation | 192.6±5.95µs | **182.8±14.80µs** | **-5.09%** |
| Array update evaluation | 431.1±7.90µs | 435.5±21.62µs | +1.02% |
| Core + Standard library compilation | 16.7±0.18ms | 16.8±0.13ms | +0.60% |
| Deutsch-Jozsa evaluation | 5.1±0.05ms | 5.1±0.05ms | 0.00% |
| Large file parity evaluation | 33.8±0.14ms | 33.8±0.19ms | 0.00% |
| Large input file compilation | 11.2±0.13ms | **11.0±0.06ms** | **-1.79%** |
| Large input file compilation (interpreter) | 43.5±1.10ms | 43.1±1.06ms | -0.92% |
| Large nested iteration | 34.2±0.29ms | 34.2±1.76ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1499.9±46.52µs | 1488.7±54.86µs | -0.75% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.7±0.07ms | **7.6±0.07ms** | **-1.30%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1415.0±32.11µs | 1402.5±50.89µs | -0.88% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | **21.1±0.47ms** | 21.3±0.11ms | **+0.95%** |
| Teleport evaluation | 82.4±6.18µs | 83.0±4.11µs | +0.73% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for f4d07a79b015a062f53adeddaea88dddf781ea8e

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for f4d07a7
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 353.4±1.85µs | **344.5±9.28µs** | **-2.52%** |
| Array literal evaluation | 192.5±0.81µs | **184.0±3.94µs** | **-4.42%** |
| Array update evaluation | 435.2±2.70µs | **425.6±2.39µs** | **-2.21%** |
| Core + Standard library compilation | 19.6±0.94ms | 19.5±0.99ms | -0.51% |
| Deutsch-Jozsa evaluation | **5.1±0.04ms** | 5.2±0.05ms | **+1.96%** |
| Large file parity evaluation | 34.1±0.22ms | 34.0±0.15ms | -0.29% |
| Large input file compilation | 12.6±0.48ms | 12.4±0.45ms | -1.59% |
| Large input file compilation (interpreter) | 49.3±1.50ms | 49.5±1.50ms | +0.41% |
| Large nested iteration | 34.7±0.31ms | **33.4±0.17ms** | **-3.75%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1523.3±82.64µs | 1493.4±40.10µs | -1.96% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.1±0.15ms | **7.9±0.19ms** | **-2.47%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1438.9±67.38µs | 1414.8±45.24µs | -1.67% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.9±0.23ms | 21.9±0.38ms | 0.00% |
| Teleport evaluation | 81.6±3.58µs | 83.7±4.26µs | +2.57% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 030a46e43b6be6fd8a88124391d645be7d8f738c

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 030a46e
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 347.1±2.99µs | **336.1±1.81µs** | **-3.17%** |
| Array literal evaluation | **174.0±1.36µs** | 179.1±4.99µs | **+2.93%** |
| Array update evaluation | 429.3±2.52µs | **419.4±2.29µs** | **-2.31%** |
| Core + Standard library compilation | 17.7±0.56ms | **16.7±0.07ms** | **-5.65%** |
| Deutsch-Jozsa evaluation | **5.0±0.04ms** | 5.1±0.05ms | **+2.00%** |
| Large file parity evaluation | 33.6±0.11ms | 33.6±0.33ms | 0.00% |
| Large input file compilation | 11.2±0.07ms | **11.1±0.07ms** | **-0.89%** |
| Large input file compilation (interpreter) | 47.1±1.35ms | **42.7±0.84ms** | **-9.34%** |
| Large nested iteration | 33.5±0.38ms | **33.0±0.47ms** | **-1.49%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1501.1±46.35µs | 1486.8±67.14µs | -0.95% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.7±0.20ms | 7.7±0.10ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1407.5±29.35µs | 1391.4±39.05µs | -1.14% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.4±0.23ms | 21.2±0.25ms | -0.93% |
| Teleport evaluation | 80.5±3.90µs | 79.3±3.47µs | -1.49% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 2d32ac572e101ec1709b17ebc0521f0e22f55ec4

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 2d32ac5
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 350.9±1.88µs | 349.9±3.55µs | -0.28% |
| Array literal evaluation | 192.5±0.67µs | **189.8±1.35µs** | **-1.40%** |
| Array update evaluation | 433.6±1.65µs | 432.0±2.32µs | -0.37% |
| Core + Standard library compilation | 18.5±0.84ms | 18.1±0.87ms | -2.16% |
| Deutsch-Jozsa evaluation | **5.0±0.05ms** | 5.1±0.09ms | **+2.00%** |
| Large file parity evaluation | 33.9±0.14ms | 33.8±0.48ms | -0.29% |
| Large input file compilation | 12.0±0.39ms | 12.0±0.50ms | 0.00% |
| Large input file compilation (interpreter) | 48.2±1.38ms | 47.5±1.15ms | -1.45% |
| Large nested iteration | 34.1±0.24ms | 34.1±0.20ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1538.1±133.29µs | 1508.3±84.82µs | -1.94% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.9±0.17ms | 8.0±0.19ms | +1.27% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1425.5±48.34µs | 1430.0±89.03µs | +0.32% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.6±0.29ms | 21.7±0.35ms | +0.46% |
| Teleport evaluation | 80.2±3.31µs | 81.0±3.82µs | +1.00% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 4679aae6d993313441a825f213f382a3143d331f

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for c6a3aab8a840c3a6845abc6ac2446fac47220beb

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for c6a3aab
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 336.6±12.49µs | 335.8±2.25µs | -0.24% |
| Array literal evaluation | 179.4±10.49µs | **170.2±2.35µs** | **-5.13%** |
| Array update evaluation | **412.0±10.11µs** | 417.8±3.47µs | **+1.41%** |
| Core + Standard library compilation | **16.3±0.48ms** | 16.8±0.58ms | **+3.07%** |
| Deutsch-Jozsa evaluation | 5.1±0.10ms | 5.1±0.06ms | 0.00% |
| Large file parity evaluation | 33.8±0.33ms | 33.7±0.52ms | -0.30% |
| Large input file compilation | 10.9±0.27ms | 10.9±0.18ms | 0.00% |
| Large input file compilation (interpreter) | 42.4±1.21ms | 42.1±0.93ms | -0.71% |
| Large nested iteration | **32.5±0.65ms** | 32.9±0.32ms | **+1.23%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1469.1±35.41µs | 1474.6±36.60µs | +0.37% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.7±0.08ms | **7.4±0.17ms** | **-3.90%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1352.8±39.73µs | 1367.3±44.38µs | +1.07% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | **20.5±0.44ms** | 21.0±0.16ms | **+2.44%** |
| Teleport evaluation | 82.3±5.50µs | 82.6±3.78µs | +0.36% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 19b46b2f491e87713860c50d31678790c81d5f39

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 7b1fe1e9233546e08b73642b43e91138d6c7e876

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for e93d61410577d1a252310ee5f1446c3551e73647

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for e93d614
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **338.1±2.72µs** | 348.4±1.66µs | **+3.05%** |
| Array literal evaluation | **180.8±4.24µs** | 193.2±1.87µs | **+6.86%** |
| Array update evaluation | **421.6±1.68µs** | 433.1±21.30µs | **+2.73%** |
| Core + Standard library compilation | 18.2±0.56ms | 18.2±0.58ms | 0.00% |
| Deutsch-Jozsa evaluation | 5.1±0.06ms | 5.1±0.16ms | 0.00% |
| Large file parity evaluation | 34.0±0.15ms | 34.0±0.57ms | 0.00% |
| Large input file compilation | 12.0±0.23ms | 12.2±0.60ms | +1.67% |
| Large input file compilation (interpreter) | 47.5±1.00ms | 48.1±1.00ms | +1.26% |
| Large nested iteration | **33.0±0.45ms** | 34.4±0.58ms | **+4.24%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1511.3±54.69µs | 1503.5±56.63µs | -0.52% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.0±0.41ms | **7.9±0.09ms** | **-1.25%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1425.4±67.30µs | 1416.4±66.75µs | -0.63% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.5±0.26ms | 21.5±0.61ms | 0.00% |
| Teleport evaluation | 83.6±5.93µs | 80.8±3.61µs | -3.35% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 502df759ab362e2f84a308d7a8e2f3dd2a65dbc4

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 502df75
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 357.9±1.39µs | **347.8±4.98µs** | **-2.82%** |
| Array literal evaluation | 201.7±3.56µs | 199.7±5.29µs | -0.99% |
| Array update evaluation | 442.0±2.91µs | **434.6±5.30µs** | **-1.67%** |
| Core + Standard library compilation | 17.3±0.38ms | **16.8±0.24ms** | **-2.89%** |
| Deutsch-Jozsa evaluation | 5.1±0.05ms | **5.0±0.05ms** | **-1.96%** |
| Large file parity evaluation | 33.7±0.12ms | 33.7±0.47ms | 0.00% |
| Large input file compilation | 11.6±0.20ms | **11.4±0.15ms** | **-1.72%** |
| Large input file compilation (interpreter) | 45.6±1.07ms | **44.1±1.57ms** | **-3.29%** |
| Large nested iteration | 35.5±0.92ms | **34.0±0.37ms** | **-4.23%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1489.6±49.44µs | 1495.1±33.94µs | +0.37% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.8±0.43ms | 7.7±0.11ms | -1.28% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1402.9±45.33µs | 1406.7±25.19µs | +0.27% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.6±0.25ms | **21.2±0.23ms** | **-1.85%** |
| Teleport evaluation | 80.5±3.52µs | 79.9±3.60µs | -0.75% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 03ab79cfd8f04dae05f18ba39c73c2cbc8a46b15

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for c648aea8c358d634ba60ce09110605c7d753b92f

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for c648aea
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 349.5±5.67µs | 346.0±6.58µs | -1.00% |
| Array literal evaluation | 199.2±2.38µs | **192.4±1.10µs** | **-3.41%** |
| Array update evaluation | 438.1±16.54µs | **428.8±1.63µs** | **-2.12%** |
| Core + Standard library compilation | 17.8±1.34ms | 17.5±0.73ms | -1.69% |
| Deutsch-Jozsa evaluation | 5.1±0.05ms | 5.1±0.20ms | 0.00% |
| Large file parity evaluation | 33.9±0.10ms | 33.8±0.61ms | -0.29% |
| Large input file compilation | **11.6±0.55ms** | 12.1±0.42ms | **+4.31%** |
| Large input file compilation (interpreter) | 47.2±2.39ms | 46.8±1.61ms | -0.85% |
| Large nested iteration | 34.1±0.40ms | 34.0±0.29ms | -0.29% |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1489.1±46.60µs | 1494.6±30.19µs | +0.37% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.9±0.28ms | 7.9±0.14ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1404.2±37.69µs | 1430.8±87.77µs | +1.89% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.3±0.30ms | 21.4±0.50ms | +0.47% |
| Teleport evaluation | 83.3±3.42µs | 81.9±3.57µs | -1.68% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for df5318e865dfc17ea6712afc546a8cfbe1c555cb

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 18a47507246482e10c7c95f0a259f1f3ad906c1f

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 18a4750
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 338.1±9.93µs | 341.1±14.17µs | +0.89% |
| Array literal evaluation | **175.1±3.14µs** | 182.5±4.89µs | **+4.23%** |
| Array update evaluation | **419.3±4.41µs** | 426.8±15.84µs | **+1.79%** |
| Core + Standard library compilation | 16.9±0.22ms | 16.9±0.29ms | 0.00% |
| Deutsch-Jozsa evaluation | 5.0±0.04ms | 5.0±0.04ms | 0.00% |
| Large file parity evaluation | 33.7±0.12ms | 33.6±0.12ms | -0.30% |
| Large input file compilation | **11.2±0.08ms** | 11.3±0.33ms | **+0.89%** |
| Large input file compilation (interpreter) | 43.7±0.94ms | 43.1±0.80ms | -1.37% |
| Large nested iteration | 33.1±0.92ms | **32.6±0.24ms** | **-1.51%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1491.2±29.05µs | 1496.0±51.30µs | +0.32% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | **7.6±0.09ms** | 7.7±0.07ms | **+1.32%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1406.6±42.76µs | 1407.2±29.61µs | +0.04% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.4±0.15ms | 21.4±0.20ms | 0.00% |
| Teleport evaluation | 79.7±3.43µs | 80.6±9.06µs | +1.13% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 7fca193b51225d830e9ee724d018727295bdf9e1

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 7fca193
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 352.0±3.46µs | **346.6±2.50µs** | **-1.53%** |
| Array literal evaluation | **192.9±1.57µs** | 197.6±3.86µs | **+2.44%** |
| Array update evaluation | 432.0±1.95µs | 433.0±2.57µs | +0.23% |
| Core + Standard library compilation | 18.8±1.27ms | 19.0±1.09ms | +1.06% |
| Deutsch-Jozsa evaluation | 5.1±0.04ms | **5.0±0.05ms** | **-1.96%** |
| Large file parity evaluation | 34.2±0.16ms | 34.1±0.22ms | -0.29% |
| Large input file compilation | 12.4±0.57ms | 12.6±0.65ms | +1.61% |
| Large input file compilation (interpreter) | 50.0±2.17ms | 51.4±3.05ms | +2.80% |
| Large nested iteration | 34.3±0.33ms | 34.1±0.35ms | -0.58% |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1512.8±92.03µs | 1533.3±112.93µs | +1.36% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.0±0.19ms | 8.0±0.19ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1430.2±117.70µs | 1436.6±101.38µs | +0.45% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 22.0±0.41ms | 21.9±0.50ms | -0.45% |
| Teleport evaluation | 81.8±4.92µs | 79.1±3.96µs | -3.30% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 17113f883113478b1f9e46a1a36d04d820b2092d

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for d344cbbf966d3dd8cdab6eb4468a97108607ff78

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for d344cbb
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **337.6±4.16µs** | 346.4±3.12µs | **+2.61%** |
| Array literal evaluation | **173.8±2.36µs** | 195.9±4.00µs | **+12.72%** |
| Array update evaluation | **419.1±3.66µs** | 429.2±1.54µs | **+2.41%** |
| Core + Standard library compilation | 16.7±0.29ms | 16.7±0.07ms | 0.00% |
| Deutsch-Jozsa evaluation | **5.0±0.03ms** | 5.1±0.06ms | **+2.00%** |
| Large file parity evaluation | 33.5±0.11ms | 33.5±0.21ms | 0.00% |
| Large input file compilation | 11.2±0.07ms | 11.2±0.16ms | 0.00% |
| Large input file compilation (interpreter) | 42.6±0.88ms | 42.4±0.78ms | -0.47% |
| Large nested iteration | **33.1±0.90ms** | 33.9±0.32ms | **+2.42%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1478.5±40.59µs | 1502.0±35.75µs | +1.59% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.6±0.34ms | 7.6±0.07ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1394.1±55.68µs | 1404.1±28.96µs | +0.72% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.2±0.14ms | 21.2±0.16ms | 0.00% |
| Teleport evaluation | 79.7±4.01µs | 79.4±3.90µs | -0.38% |

  </details>
  
github-actions[bot]: ## Benchmark for 89d551a
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **338.3±2.37µs** | 351.6±11.57µs | **+3.93%** |
| Array literal evaluation | 181.1±4.62µs | **177.2±1.25µs** | **-2.15%** |
| Array update evaluation | 421.0±1.98µs | **417.9±2.87µs** | **-0.74%** |
| Core + Standard library compilation | **17.5±0.48ms** | 18.0±0.75ms | **+2.86%** |
| Deutsch-Jozsa evaluation | 5.0±0.12ms | 5.0±0.05ms | 0.00% |
| Large file parity evaluation | 33.7±0.11ms | 33.7±0.37ms | 0.00% |
| Large input file compilation | **11.7±0.21ms** | 12.1±0.39ms | **+3.42%** |
| Large input file compilation (interpreter) | 47.2±1.45ms | 47.4±1.22ms | +0.42% |
| Large nested iteration | 33.0±0.67ms | **32.5±0.26ms** | **-1.52%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1499.3±44.06µs | 1512.4±47.61µs | +0.87% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | **7.8±0.09ms** | 7.9±0.09ms | **+1.28%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1409.2±35.61µs | 1427.9±66.68µs | +1.33% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.7±0.29ms | 21.7±0.36ms | 0.00% |
| Teleport evaluation | 80.6±3.69µs | 79.3±4.75µs | -1.61% |

  </details>
  
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 734bc2255d942f36537160830424c6fac875c6ac

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 48f50d23c9ae63ed694a2c85fa6f3840d2e4a51d

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 79a003f2b5ed1ef93c0a9b286f166288cf576c21

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for bec1cd6b027ac95a920667ca5397afc02205cea2

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: _Change in memory usage detected by benchmark._
## Memory Report for 2d86e827b1265ccb8c13df20f55b28d9ad001408

| Test                        | This Branch | On Main  | Difference |
|-----------------------------|-------------|----------| ---------- |
| compile core + standard lib | 15975609 bytes | 15969577 bytes | 6032 bytes
github-actions[bot]: ## Benchmark for 2d86e82
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **338.6±2.67µs** | 359.1±19.94µs | **+6.05%** |
| Array literal evaluation | **179.4±1.05µs** | 192.9±1.93µs | **+7.53%** |
| Array update evaluation | **422.5±3.88µs** | 442.1±12.13µs | **+4.64%** |
| Core + Standard library compilation | 19.3±0.98ms | **16.9±0.19ms** | **-12.44%** |
| Deutsch-Jozsa evaluation | 5.2±0.07ms | 5.2±0.44ms | 0.00% |
| Large file parity evaluation | 33.9±0.14ms | **33.7±0.34ms** | **-0.59%** |
| Large input file compilation | 12.5±0.25ms | **11.4±0.19ms** | **-8.80%** |
| Large input file compilation (interpreter) | 49.5±1.23ms | **44.2±1.42ms** | **-10.71%** |
| Large nested iteration | **33.2±1.26ms** | 34.4±0.25ms | **+3.61%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1510.5±70.51µs | 1513.7±57.23µs | +0.21% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.1±0.13ms | 8.1±0.20ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1423.0±101.82µs | 1422.6±72.36µs | -0.03% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.7±0.22ms | **21.2±0.30ms** | **-2.30%** |
| Teleport evaluation | 83.6±3.48µs | **80.1±3.69µs** | **-4.19%** |

  </details>
  

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 65557b0b..45bbaa08 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -927,6 +927,7 @@ dependencies = [
  "qsc_frontend",
  "qsc_hir",
  "qsc_linter",
+ "qsc_lowerer",
  "qsc_passes",
  "qsc_project",
  "qsc_rca",
@@ -980,7 +981,10 @@ dependencies = [
  "qsc_fir",
  "qsc_frontend",
  "qsc_hir",
+ "qsc_lowerer",
+ "qsc_partial_eval",
  "qsc_passes",
+ "qsc_rca",
  "qsc_rir",
  "rustc-hash",
 ]
@@ -1021,6 +1025,7 @@ dependencies = [
  "qsc_fir",
  "qsc_frontend",
  "qsc_hir",
+ "qsc_lowerer",
  "qsc_passes",
  "quantum-sparse-sim",
  "rand",
@@ -1094,6 +1099,15 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "qsc_lowerer"
+version = "0.0.0"
+dependencies = [
+ "qsc_data_structures",
+ "qsc_fir",
+ "qsc_hir",
+]
+
 [[package]]
 name = "qsc_parse"
 version = "0.0.0"
@@ -1121,9 +1135,11 @@ dependencies = [
  "qsc_eval",
  "qsc_fir",
  "qsc_frontend",
+ "qsc_lowerer",
  "qsc_rca",
  "qsc_rir",
  "rustc-hash",
+ "thiserror",
 ]
 
 [[package]]
@@ -1139,6 +1155,7 @@ dependencies = [
  "qsc_fir",
  "qsc_frontend",
  "qsc_hir",
+ "qsc_lowerer",
  "qsc_rca",
  "rustc-hash",
  "thiserror",
@@ -1168,9 +1185,9 @@ dependencies = [
  "indenter",
  "qsc",
  "qsc_data_structures",
- "qsc_eval",
  "qsc_fir",
  "qsc_frontend",
+ "qsc_lowerer",
  "qsc_passes",
  "rustc-hash",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 91efd749..f0fd67ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ members = [
     "compiler/qsc_frontend",
     "compiler/qsc_hir",
     "compiler/qsc_linter",
+    "compiler/qsc_lowerer",
     "compiler/qsc_parse",
     "compiler/qsc_partial_eval",
     "compiler/qsc_passes",
diff --git a/compiler/qsc/Cargo.toml b/compiler/qsc/Cargo.toml
index 5bc5069e..74aa6f10 100644
--- a/compiler/qsc/Cargo.toml
+++ b/compiler/qsc/Cargo.toml
@@ -23,6 +23,7 @@ qsc_formatter = { path = "../qsc_formatter" }
 qsc_eval = { path = "../qsc_eval" }
 qsc_frontend = { path = "../qsc_frontend" }
 qsc_linter = { path = "../qsc_linter" }
+qsc_lowerer = { path = "../qsc_lowerer" }
 qsc_ast = { path = "../qsc_ast" }
 qsc_fir = { path = "../qsc_fir" }
 qsc_hir = { path = "../qsc_hir" }
diff --git a/compiler/qsc/benches/rca.rs b/compiler/qsc/benches/rca.rs
index f566620f..4a63359c 100644
--- a/compiler/qsc/benches/rca.rs
+++ b/compiler/qsc/benches/rca.rs
@@ -4,9 +4,9 @@
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::incremental::Compiler;
 use qsc_data_structures::language_features::LanguageFeatures;
-use qsc_eval::{debug::map_hir_package_to_fir, lower::Lowerer};
 use qsc_fir::fir::PackageStore;
 use qsc_frontend::compile::{PackageStore as HirPackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::{map_hir_package_to_fir, Lowerer};
 use qsc_passes::PackageType;
 use qsc_rca::{Analyzer, PackageStoreComputeProperties};
 
diff --git a/compiler/qsc/src/codegen.rs b/compiler/qsc/src/codegen.rs
new file mode 100644
index 00000000..8dd19224
--- /dev/null
+++ b/compiler/qsc/src/codegen.rs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use qsc_codegen::qir::hir_to_qir;
+use qsc_data_structures::language_features::LanguageFeatures;
+use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_passes::{PackageType, PassContext};
+
+use crate::compile;
+
+pub fn get_qir(
+    sources: SourceMap,
+    language_features: LanguageFeatures,
+    capabilities: RuntimeCapabilityFlags,
+) -> Result<String, String> {
+    let core = compile::core();
+    let mut package_store = PackageStore::new(core);
+    let std = compile::std(&package_store, capabilities);
+    let std = package_store.insert(std);
+
+    let (unit, errors) = crate::compile::compile(
+        &package_store,
+        &[std],
+        sources,
+        PackageType::Exe,
+        capabilities,
+        language_features,
+    );
+
+    // Ensure it compiles before trying to add it to the store.
+    if !errors.is_empty() {
+        // This should never happen, as the program should be checked for errors before trying to
+        // generate code for it. But just in case, simply report the failure.
+        return Err("Failed to generate QIR".to_string());
+    }
+
+    let package_id = package_store.insert(unit);
+
+    let caps_results = PassContext::run_fir_passes_on_hir(&package_store, package_id, capabilities);
+    // Ensure it compiles before trying to add it to the store.
+    match caps_results {
+        Ok(compute_properties) => hir_to_qir(
+            &package_store,
+            package_id,
+            capabilities,
+            Some(compute_properties),
+        )
+        .map_err(|e| e.to_string()),
+        Err(_) => {
+            // This should never happen, as the program should be checked for errors before trying to
+            // generate code for it. But just in case, simply report the failure.
+            Err("Failed to generate QIR".to_string())
+        }
+    }
+}
diff --git a/compiler/qsc/src/interpret.rs b/compiler/qsc/src/interpret.rs
index 81d7e43c..452ee0c9 100644
--- a/compiler/qsc/src/interpret.rs
+++ b/compiler/qsc/src/interpret.rs
@@ -23,6 +23,7 @@ pub use qsc_eval::{
     val::Value,
     StepAction, StepResult,
 };
+use qsc_lowerer::{map_fir_package_to_hir, map_hir_package_to_fir};
 
 use crate::{
     error::{self, WithStack},
@@ -46,7 +47,6 @@ use qsc_data_structures::{
 };
 use qsc_eval::{
     backend::{Backend, Chain as BackendChain, SparseSim},
-    debug::{map_fir_package_to_hir, map_hir_package_to_fir},
     output::Receiver,
     val, Env, State, VariableInfo,
 };
@@ -59,7 +59,7 @@ use qsc_frontend::{
     compile::{CompileUnit, PackageStore, RuntimeCapabilityFlags, Source, SourceMap},
     error::WithSource,
 };
-use qsc_passes::PackageType;
+use qsc_passes::{PackageType, PassContext};
 use rustc_hash::FxHashSet;
 use thiserror::Error;
 
@@ -112,7 +112,7 @@ pub struct Interpreter {
     // The FIR store
     fir_store: fir::PackageStore,
     /// FIR lowerer
-    lowerer: qsc_eval::lower::Lowerer,
+    lowerer: qsc_lowerer::Lowerer,
     /// The ID of the current package.
     /// This ID is valid both for the FIR store and the `PackageStore`.
     package: PackageId,
@@ -190,7 +190,7 @@ impl Interpreter {
         for (id, unit) in compiler.package_store() {
             fir_store.insert(
                 map_hir_package_to_fir(id),
-                qsc_eval::lower::Lowerer::new()
+                qsc_lowerer::Lowerer::new()
                     .with_debug(dbg)
                     .lower_package(&unit.package),
             );
@@ -203,7 +203,7 @@ impl Interpreter {
             lines: 0,
             capabilities,
             fir_store,
-            lowerer: qsc_eval::lower::Lowerer::new().with_debug(dbg),
+            lowerer: qsc_lowerer::Lowerer::new().with_debug(dbg),
             env: Env::default(),
             sim: BackendChain::new(
                 SparseSim::new(),
@@ -300,7 +300,7 @@ impl Interpreter {
             .compile_fragments_fail_fast(&label, fragments)
             .map_err(into_errors)?;
 
-        let (_, graph) = self.lower(&increment);
+        let (_, graph) = self.lower(&increment)?;
 
         // Updating the compiler state with the new AST/HIR nodes
         // is not necessary for the interpreter to function, as all
@@ -432,7 +432,7 @@ impl Interpreter {
 
         // `lower` will update the entry expression in the FIR store,
         // and it will always return an empty list of statements.
-        let (_, graph) = self.lower(&increment);
+        let (_, graph) = self.lower(&increment)?;
 
         // The AST and HIR packages in `increment` only contain an entry
         // expression and no statements. The HIR *can* contain items if the entry
@@ -454,13 +454,52 @@ impl Interpreter {
     fn lower(
         &mut self,
         unit_addition: &qsc_frontend::incremental::Increment,
-    ) -> (Vec<StmtId>, Vec<ExecGraphNode>) {
+    ) -> core::result::Result<(Vec<StmtId>, Vec<ExecGraphNode>), Vec<Error>> {
+        if self.capabilities != RuntimeCapabilityFlags::all() {
+            return self.run_fir_passes(unit_addition);
+        }
         let fir_package = self.fir_store.get_mut(self.package);
-        (
+        Ok((
             self.lowerer
                 .lower_and_update_package(fir_package, &unit_addition.hir),
             self.lowerer.take_exec_graph(),
-        )
+        ))
+    }
+
+    fn run_fir_passes(
+        &mut self,
+        unit: &qsc_frontend::incremental::Increment,
+    ) -> std::result::Result<(Vec<StmtId>, Vec<ExecGraphNode>), Vec<Error>> {
+        let fir_package = self.fir_store.get_mut(self.package);
+        let stmts = self
+            .lowerer
+            .lower_and_update_package(fir_package, &unit.hir);
+
+        let cap_results =
+            PassContext::run_fir_passes_on_fir(&self.fir_store, self.package, self.capabilities);
+
+        let Err(caps_errors) = cap_results else {
+            let graph = self.lowerer.take_exec_graph();
+            return Ok((stmts, graph));
+        };
+
+        // if there are errors, convert them to interpreter errors
+        // and don't update the lowerer or FIR store.
+        let mut errors = Vec::with_capacity(caps_errors.len());
+        let source_package = self
+            .compiler
+            .package_store()
+            .get(map_fir_package_to_hir(self.package))
+            .expect("package should exist in the package store");
+
+        for error in caps_errors {
+            errors.push(Error::Pass(WithSource::from_map(
+                &source_package.sources,
+                error,
+            )));
+        }
+
+        Err(errors)
     }
 
     fn next_line_label(&mut self) -> String {
diff --git a/compiler/qsc/src/interpret/debug.rs b/compiler/qsc/src/interpret/debug.rs
index 7674fc5e..013075e7 100644
--- a/compiler/qsc/src/interpret/debug.rs
+++ b/compiler/qsc/src/interpret/debug.rs
@@ -4,11 +4,12 @@
 #[cfg(test)]
 mod tests;
 
-use qsc_eval::debug::{map_fir_package_to_hir, Frame};
+use qsc_eval::debug::Frame;
 use qsc_fir::fir::{Global, PackageStoreLookup, StoreItemId};
 use qsc_frontend::compile::PackageStore;
 use qsc_hir::hir;
 use qsc_hir::hir::{Item, ItemKind};
+use qsc_lowerer::map_fir_package_to_hir;
 
 #[must_use]
 pub(crate) fn format_call_stack(
diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs
index 6666a7f3..c20827ee 100644
--- a/compiler/qsc/src/lib.rs
+++ b/compiler/qsc/src/lib.rs
@@ -1,6 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+pub mod codegen;
 pub mod compile;
 pub mod error;
 pub mod incremental;
diff --git a/compiler/qsc/src/target.rs b/compiler/qsc/src/target.rs
index e08a7073..04b9bf9b 100644
--- a/compiler/qsc/src/target.rs
+++ b/compiler/qsc/src/target.rs
@@ -9,6 +9,7 @@ use qsc_frontend::compile::RuntimeCapabilityFlags;
 pub enum Profile {
     Unrestricted,
     Base,
+    Adaptive,
 }
 
 impl Profile {
@@ -17,6 +18,7 @@ impl Profile {
         match self {
             Self::Unrestricted => "Unrestricted",
             Self::Base => "Base",
+            Self::Adaptive => "Adaptive",
         }
     }
 }
@@ -26,6 +28,7 @@ impl From<Profile> for RuntimeCapabilityFlags {
         match value {
             Profile::Unrestricted => Self::all(),
             Profile::Base => Self::empty(),
+            Profile::Adaptive => Self::ForwardBranching,
         }
     }
 }
@@ -35,8 +38,9 @@ impl FromStr for Profile {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "Unrestricted" | "unrestricted" => Ok(Self::Unrestricted),
+            "Adaptive" | "adaptive" => Ok(Self::Adaptive),
             "Base" | "base" => Ok(Self::Base),
+            "Unrestricted" | "unrestricted" => Ok(Self::Unrestricted),
             _ => Err(()),
         }
     }
diff --git a/compiler/qsc_codegen/Cargo.toml b/compiler/qsc_codegen/Cargo.toml
index 902ef4fc..0ffe796e 100644
--- a/compiler/qsc_codegen/Cargo.toml
+++ b/compiler/qsc_codegen/Cargo.toml
@@ -12,11 +12,14 @@ license.workspace = true
 num-bigint = { workspace = true }
 num-complex = { workspace = true }
 rustc-hash = { workspace = true }
-qsc_eval = { path = "../qsc_eval" }
 qsc_data_structures = { path = "../qsc_data_structures" }
-qsc_frontend = { path = "../qsc_frontend" }
+qsc_eval = { path = "../qsc_eval" }
 qsc_fir = { path = "../qsc_fir" }
+qsc_frontend = { path = "../qsc_frontend" }
 qsc_hir = { path = "../qsc_hir" }
+qsc_lowerer = { path = "../qsc_lowerer" }
+qsc_partial_eval = { path = "../qsc_partial_eval" }
+qsc_rca = { path = "../qsc_rca" }
 qsc_rir = { path = "../qsc_rir" }
 
 [dev-dependencies]
diff --git a/compiler/qsc_codegen/src/qir.rs b/compiler/qsc_codegen/src/qir.rs
index be24b378..2e3f3fa9 100644
--- a/compiler/qsc_codegen/src/qir.rs
+++ b/compiler/qsc_codegen/src/qir.rs
@@ -7,11 +7,65 @@ mod instruction_tests;
 #[cfg(test)]
 mod tests;
 
+use qsc_frontend::compile::RuntimeCapabilityFlags;
+use qsc_hir::hir;
+use qsc_lowerer::map_hir_package_to_fir;
+use qsc_partial_eval::partially_evaluate;
+use qsc_rca::PackageStoreComputeProperties;
 use qsc_rir::{
+    passes::{check_and_transform, defer_quantum_measurements},
     rir::{self, ConditionCode},
     utils::get_all_block_successors,
 };
 
+fn lower_store(package_store: &qsc_frontend::compile::PackageStore) -> qsc_fir::fir::PackageStore {
+    let mut fir_store = qsc_fir::fir::PackageStore::new();
+    for (id, unit) in package_store {
+        let package = qsc_lowerer::Lowerer::new().lower_package(&unit.package);
+        fir_store.insert(map_hir_package_to_fir(id), package);
+    }
+    fir_store
+}
+
+/// converts the given sources to QIR using the given language features.
+pub fn hir_to_qir(
+    package_store: &qsc_frontend::compile::PackageStore,
+    package_id: hir::PackageId,
+    capabilities: RuntimeCapabilityFlags,
+    compute_properties: Option<PackageStoreComputeProperties>,
+) -> Result<String, qsc_partial_eval::Error> {
+    let fir_store = lower_store(package_store);
+    let fir_package_id = map_hir_package_to_fir(package_id);
+    fir_to_qir(&fir_store, fir_package_id, capabilities, compute_properties)
+}
+
+pub fn fir_to_qir(
+    fir_store: &qsc_fir::fir::PackageStore,
+    fir_package_id: qsc_fir::fir::PackageId,
+    capabilities: RuntimeCapabilityFlags,
+    compute_properties: Option<PackageStoreComputeProperties>,
+) -> Result<String, qsc_partial_eval::Error> {
+    let mut program = get_rir_from_compilation(fir_store, fir_package_id, compute_properties)?;
+    check_and_transform(&mut program);
+    if capabilities.is_empty() {
+        defer_quantum_measurements(&mut program);
+    }
+    Ok(ToQir::<String>::to_qir(&program, &program))
+}
+
+fn get_rir_from_compilation(
+    fir_store: &qsc_fir::fir::PackageStore,
+    fir_package_id: qsc_fir::fir::PackageId,
+    compute_properties: Option<PackageStoreComputeProperties>,
+) -> Result<rir::Program, qsc_partial_eval::Error> {
+    let compute_properties = compute_properties.unwrap_or_else(|| {
+        let analyzer = qsc_rca::Analyzer::init(fir_store);
+        analyzer.analyze_all()
+    });
+
+    partially_evaluate(fir_package_id, fir_store, &compute_properties)
+}
+
 /// A trait for converting a type into QIR of type `T`.
 /// This can be used to generate QIR strings or other representations.
 pub trait ToQir<T> {
diff --git a/compiler/qsc_codegen/src/qir_base.rs b/compiler/qsc_codegen/src/qir_base.rs
index 988b3cce..6173fb65 100644
--- a/compiler/qsc_codegen/src/qir_base.rs
+++ b/compiler/qsc_codegen/src/qir_base.rs
@@ -8,16 +8,12 @@ use crate::remapper::{HardwareId, Remapper};
 use num_bigint::BigUint;
 use num_complex::Complex;
 use qsc_eval::{
-    backend::Backend,
-    debug::{map_hir_package_to_fir, Frame},
-    eval,
-    output::GenericReceiver,
-    val::Value,
-    Env, Error,
+    backend::Backend, debug::Frame, eval, output::GenericReceiver, val::Value, Env, Error,
 };
 use qsc_fir::fir;
 use qsc_frontend::compile::PackageStore;
 use qsc_hir::hir::{self};
+use qsc_lowerer::map_hir_package_to_fir;
 use rustc_hash::FxHashSet;
 use std::fmt::{Display, Write};
 
@@ -35,7 +31,7 @@ pub fn generate_qir(
     for (id, unit) in store {
         fir_store.insert(
             map_hir_package_to_fir(id),
-            qsc_eval::lower::Lowerer::new().lower_package(&unit.package),
+            qsc_lowerer::Lowerer::new().lower_package(&unit.package),
         );
     }
 
diff --git a/compiler/qsc_data_structures/src/language_features.rs b/compiler/qsc_data_structures/src/language_features.rs
index f3d5105c..e6a4094c 100644
--- a/compiler/qsc_data_structures/src/language_features.rs
+++ b/compiler/qsc_data_structures/src/language_features.rs
@@ -10,6 +10,7 @@ pub struct LanguageFeatures(u8);
 bitflags! {
     impl LanguageFeatures: u8 {
         const V2PreviewSyntax = 0b1;
+        const PreviewQirGen = 0b10;
     }
 }
 
@@ -33,6 +34,7 @@ where
         iter.into_iter().fold(LanguageFeatures::empty(), |acc, x| {
             acc | match x.as_ref() {
                 "v2-preview-syntax" => LanguageFeatures::V2PreviewSyntax,
+                "preview-qir-gen" => LanguageFeatures::PreviewQirGen,
                 _ => LanguageFeatures::empty(),
             }
         })
diff --git a/compiler/qsc_eval/Cargo.toml b/compiler/qsc_eval/Cargo.toml
index f3bd6560..366a1ea2 100644
--- a/compiler/qsc_eval/Cargo.toml
+++ b/compiler/qsc_eval/Cargo.toml
@@ -17,6 +17,7 @@ quantum-sparse-sim = { workspace = true }
 qsc_data_structures = { path = "../qsc_data_structures" }
 qsc_fir = { path = "../qsc_fir" }
 qsc_hir = { path = "../qsc_hir" }
+qsc_lowerer = { path = "../qsc_lowerer" }
 rand =  { workspace = true }
 rustc-hash = { workspace = true }
 thiserror = { workspace = true }
diff --git a/compiler/qsc_eval/src/debug.rs b/compiler/qsc_eval/src/debug.rs
index becd030b..3dd4ff0a 100644
--- a/compiler/qsc_eval/src/debug.rs
+++ b/compiler/qsc_eval/src/debug.rs
@@ -4,9 +4,7 @@
 use qsc_data_structures::span::Span;
 
 use qsc_data_structures::functors::FunctorApp;
-use qsc_fir::fir;
 use qsc_fir::fir::{PackageId, StoreItemId};
-use qsc_hir::hir;
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct Frame {
@@ -45,13 +43,3 @@ impl CallStack {
         self.frames.pop()
     }
 }
-
-#[must_use]
-pub fn map_hir_package_to_fir(package: hir::PackageId) -> fir::PackageId {
-    fir::PackageId::from(<hir::PackageId as Into<usize>>::into(package))
-}
-
-#[must_use]
-pub fn map_fir_package_to_hir(package: fir::PackageId) -> hir::PackageId {
-    hir::PackageId::from(<fir::PackageId as Into<usize>>::into(package))
-}
diff --git a/compiler/qsc_eval/src/lib.rs b/compiler/qsc_eval/src/lib.rs
index d91b9b76..f6db1543 100644
--- a/compiler/qsc_eval/src/lib.rs
+++ b/compiler/qsc_eval/src/lib.rs
@@ -21,14 +21,13 @@ pub mod backend;
 pub mod debug;
 mod error;
 mod intrinsic;
-pub mod lower;
 pub mod output;
 pub mod state;
 pub mod val;
 
 use crate::val::Value;
 use backend::Backend;
-use debug::{map_fir_package_to_hir, CallStack, Frame};
+use debug::{CallStack, Frame};
 use error::PackageSpan;
 use miette::Diagnostic;
 use num_bigint::BigInt;
@@ -40,6 +39,7 @@ use qsc_fir::fir::{
     StoreItemId, StringComponent, UnOp,
 };
 use qsc_fir::ty::Ty;
+use qsc_lowerer::map_fir_package_to_hir;
 use rand::{rngs::StdRng, SeedableRng};
 use std::ops;
 use std::{
diff --git a/compiler/qsc_fir/src/fir.rs b/compiler/qsc_fir/src/fir.rs
index a0ddfef5..df84098a 100644
--- a/compiler/qsc_fir/src/fir.rs
+++ b/compiler/qsc_fir/src/fir.rs
@@ -549,7 +549,7 @@ pub trait PackageLookup {
 /// within the containing node. Node ids are used to identify nodes within
 /// the package and require mapping from the HIR node id to the new FIR node id.
 /// `PackageId`s and `LocalItemId`s are 1:1 from the HIR and are not remapped.
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 pub struct Package {
     /// The items in the package.
     pub items: IndexMap<LocalItemId, Item>,
diff --git a/compiler/qsc_frontend/src/compile.rs b/compiler/qsc_frontend/src/compile.rs
index 65a6d432..36e50978 100644
--- a/compiler/qsc_frontend/src/compile.rs
+++ b/compiler/qsc_frontend/src/compile.rs
@@ -50,16 +50,18 @@ bitflags! {
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum ConfigAttr {
-    Unrestricted,
+    Adaptive,
     Base,
+    Unrestricted,
 }
 
 impl ConfigAttr {
     #[must_use]
     pub fn to_str(&self) -> &'static str {
         match self {
-            Self::Unrestricted => "Unrestricted",
+            Self::Adaptive => "Adaptive",
             Self::Base => "Base",
+            Self::Unrestricted => "Unrestricted",
         }
     }
 
@@ -74,8 +76,9 @@ impl FromStr for ConfigAttr {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "Unrestricted" => Ok(ConfigAttr::Unrestricted),
+            "Adaptive" => Ok(ConfigAttr::Adaptive),
             "Base" => Ok(ConfigAttr::Base),
+            "Unrestricted" => Ok(ConfigAttr::Unrestricted),
             _ => Err(()),
         }
     }
@@ -86,6 +89,7 @@ impl From<ConfigAttr> for RuntimeCapabilityFlags {
         match value {
             ConfigAttr::Unrestricted => Self::all(),
             ConfigAttr::Base => Self::empty(),
+            ConfigAttr::Adaptive => Self::ForwardBranching,
         }
     }
 }
diff --git a/compiler/qsc_frontend/src/compile/preprocess.rs b/compiler/qsc_frontend/src/compile/preprocess.rs
index ae84c4b2..8d8228bb 100644
--- a/compiler/qsc_frontend/src/compile/preprocess.rs
+++ b/compiler/qsc_frontend/src/compile/preprocess.rs
@@ -119,7 +119,10 @@ impl MutVisitor for Conditional {
 }
 
 fn matches_config(attrs: &[Box<Attr>], capabilities: RuntimeCapabilityFlags) -> bool {
-    attrs.iter().all(|attr| {
+    if attrs.is_empty() {
+        return true;
+    }
+    attrs.iter().any(|attr| {
         if hir::Attr::from_str(attr.name.name.as_ref()) == Ok(hir::Attr::Config) {
             if let ExprKind::Paren(inner) = attr.arg.kind.as_ref() {
                 match inner.kind.as_ref() {
@@ -129,6 +132,9 @@ fn matches_config(attrs: &[Box<Attr>], capabilities: RuntimeCapabilityFlags) ->
                     ExprKind::Path(path) => match ConfigAttr::from_str(path.name.name.as_ref()) {
                         Ok(ConfigAttr::Unrestricted) => capabilities.is_all(),
                         Ok(ConfigAttr::Base) => capabilities.is_empty(),
+                        Ok(ConfigAttr::Adaptive) => {
+                            capabilities == RuntimeCapabilityFlags::ForwardBranching
+                        }
                         _ => true,
                     },
                     _ => true, // Unknown config attribute, so we assume it matches
diff --git a/compiler/qsc_lowerer/Cargo.toml b/compiler/qsc_lowerer/Cargo.toml
new file mode 100644
index 00000000..13a28b76
--- /dev/null
+++ b/compiler/qsc_lowerer/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "qsc_lowerer"
+authors.workspace = true
+homepage.workspace = true
+repository.workspace = true
+edition.workspace = true
+license.workspace = true
+version.workspace = true
+
+[dependencies]
+qsc_data_structures = { path = "../qsc_data_structures" }
+qsc_fir = { path = "../qsc_fir" }
+qsc_hir = { path = "../qsc_hir" }
+
+[lints]
+workspace = true
diff --git a/compiler/qsc_eval/src/lower.rs b/compiler/qsc_lowerer/src/lib.rs
similarity index 99%
rename from compiler/qsc_eval/src/lower.rs
rename to compiler/qsc_lowerer/src/lib.rs
index fd36d962..570ddde7 100644
--- a/compiler/qsc_eval/src/lower.rs
+++ b/compiler/qsc_lowerer/src/lib.rs
@@ -12,6 +12,16 @@ use qsc_hir::hir::{self, SpecBody, SpecGen};
 use std::iter::once;
 use std::{clone::Clone, rc::Rc};
 
+#[must_use]
+pub fn map_hir_package_to_fir(package: hir::PackageId) -> fir::PackageId {
+    fir::PackageId::from(Into::<usize>::into(package))
+}
+
+#[must_use]
+pub fn map_fir_package_to_hir(package: fir::PackageId) -> hir::PackageId {
+    hir::PackageId::from(Into::<usize>::into(package))
+}
+
 pub struct Lowerer {
     nodes: IndexMap<hir::NodeId, fir::NodeId>,
     locals: IndexMap<hir::NodeId, fir::LocalVarId>,
diff --git a/compiler/qsc_partial_eval/Cargo.toml b/compiler/qsc_partial_eval/Cargo.toml
index fcad17e2..b9191ca5 100644
--- a/compiler/qsc_partial_eval/Cargo.toml
+++ b/compiler/qsc_partial_eval/Cargo.toml
@@ -14,8 +14,10 @@ rustc-hash = { workspace = true }
 qsc_data_structures = { path = "../qsc_data_structures" }
 qsc_eval = { path = "../qsc_eval" }
 qsc_fir = { path = "../qsc_fir" }
+qsc_lowerer = { path = "../qsc_lowerer" }
 qsc_rca = { path = "../qsc_rca" }
 qsc_rir = { path = "../qsc_rir" }
+thiserror = { workspace = true }
 
 [dev-dependencies]
 expect-test = { workspace = true }
diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs
index 709610f9..840838b5 100644
--- a/compiler/qsc_partial_eval/src/lib.rs
+++ b/compiler/qsc_partial_eval/src/lib.rs
@@ -4,6 +4,7 @@
 #[cfg(test)]
 mod tests;
 
+use miette::Diagnostic;
 use qsc_data_structures::functors::FunctorApp;
 use qsc_eval::{
     self, backend::Backend, exec_graph_section, output::GenericReceiver, val::Value, Env, State,
@@ -22,6 +23,7 @@ use qsc_rca::{ComputeKind, ComputePropertiesLookup, PackageStoreComputePropertie
 use qsc_rir::rir::{self, Callable, CallableId, CallableType, Instruction, Literal, Program};
 use rustc_hash::FxHashMap;
 use std::{collections::hash_map::Entry, rc::Rc, result::Result};
+use thiserror::Error;
 
 pub fn partially_evaluate(
     package_id: PackageId,
@@ -32,7 +34,10 @@ pub fn partially_evaluate(
     partial_evaluator.eval()
 }
 
+#[derive(Clone, Debug, Diagnostic, Error)]
 pub enum Error {
+    #[error("partial evaluation error: {0}")]
+    #[diagnostic(code("Qsc.PartialEval.EvaluationFailed"))]
     EvaluationFailed(qsc_eval::Error),
 }
 
diff --git a/compiler/qsc_passes/Cargo.toml b/compiler/qsc_passes/Cargo.toml
index dae659c5..7a39dbfe 100644
--- a/compiler/qsc_passes/Cargo.toml
+++ b/compiler/qsc_passes/Cargo.toml
@@ -11,9 +11,11 @@ license.workspace = true
 [dependencies]
 miette = { workspace = true }
 qsc_data_structures = { path = "../qsc_data_structures" }
+qsc_eval = { path = "../qsc_eval" }
 qsc_fir = { path = "../qsc_fir" }
 qsc_frontend = { path = "../qsc_frontend" }
 qsc_hir = { path = "../qsc_hir" }
+qsc_lowerer = { path = "../qsc_lowerer" }
 qsc_rca = { path = "../qsc_rca" }
 rustc-hash = { workspace = true }
 thiserror = { workspace = true }
diff --git a/compiler/qsc_passes/src/capabilitiesck.rs b/compiler/qsc_passes/src/capabilitiesck.rs
index cb71d3c6..e0478f48 100644
--- a/compiler/qsc_passes/src/capabilitiesck.rs
+++ b/compiler/qsc_passes/src/capabilitiesck.rs
@@ -15,6 +15,7 @@ pub mod tests_common;
 
 use miette::Diagnostic;
 use qsc_data_structures::span::Span;
+
 use qsc_fir::{
     fir::{
         Block, BlockId, CallableImpl, Expr, ExprId, ExprKind, Global, Ident, Item, ItemKind,
@@ -25,7 +26,11 @@ use qsc_fir::{
     visit::Visitor,
 };
 use qsc_frontend::compile::RuntimeCapabilityFlags;
-use qsc_rca::{ComputeKind, ItemComputeProperties, PackageComputeProperties, RuntimeFeatureFlags};
+use qsc_lowerer::map_hir_package_to_fir;
+use qsc_rca::{
+    Analyzer, ComputeKind, ItemComputeProperties, PackageComputeProperties,
+    PackageStoreComputeProperties, RuntimeFeatureFlags,
+};
 use rustc_hash::FxHashMap;
 use thiserror::Error;
 
@@ -168,6 +173,42 @@ pub enum Error {
     UseOfClosure(#[label] Span),
 }
 
+/// Lower a package store from `qsc_frontend` HIR store to a `qsc_fir` FIR store.
+pub fn lower_store(
+    package_store: &qsc_frontend::compile::PackageStore,
+) -> qsc_fir::fir::PackageStore {
+    let mut fir_store = qsc_fir::fir::PackageStore::new();
+    for (id, unit) in package_store {
+        let package = qsc_lowerer::Lowerer::new().lower_package(&unit.package);
+        fir_store.insert(map_hir_package_to_fir(id), package);
+    }
+    fir_store
+}
+
+pub fn run_rca_pass(
+    fir_store: &qsc_fir::fir::PackageStore,
+    package_id: qsc_fir::fir::PackageId,
+    capabilities: RuntimeCapabilityFlags,
+) -> Result<PackageStoreComputeProperties, Vec<crate::Error>> {
+    let analyzer = Analyzer::init(fir_store);
+    let compute_properties = analyzer.analyze_all();
+    let fir_package = fir_store.get(package_id);
+
+    let package_compute_properties = compute_properties.get(package_id);
+    let mut errors =
+        check_supported_capabilities(fir_package, package_compute_properties, capabilities);
+
+    if errors.is_empty() {
+        Ok(compute_properties)
+    } else {
+        let errors = errors
+            .drain(..)
+            .map(crate::Error::CapabilitiesCk)
+            .collect::<Vec<_>>();
+        Err(errors)
+    }
+}
+
 #[must_use]
 pub fn check_supported_capabilities(
     package: &Package,
diff --git a/compiler/qsc_passes/src/lib.rs b/compiler/qsc_passes/src/lib.rs
index bc93bd5c..ae82a9ce 100644
--- a/compiler/qsc_passes/src/lib.rs
+++ b/compiler/qsc_passes/src/lib.rs
@@ -16,7 +16,7 @@ mod replace_qubit_allocation;
 mod spec_gen;
 
 use callable_limits::CallableLimits;
-use capabilitiesck::check_supported_capabilities;
+use capabilitiesck::{check_supported_capabilities, lower_store, run_rca_pass};
 use entry_point::generate_entry_expr;
 use loop_unification::LoopUni;
 use miette::Diagnostic;
@@ -30,7 +30,8 @@ use qsc_hir::{
     validate::Validator,
     visit::Visitor,
 };
-use qsc_rca::PackageComputeProperties;
+use qsc_lowerer::map_hir_package_to_fir;
+use qsc_rca::{PackageComputeProperties, PackageStoreComputeProperties};
 use replace_qubit_allocation::ReplaceQubitAllocation;
 use thiserror::Error;
 
@@ -118,6 +119,24 @@ impl PassContext {
             .chain(base_prof_errors.into_iter().map(Error::BaseProfCk))
             .collect()
     }
+
+    pub fn run_fir_passes_on_hir(
+        package_store: &qsc_frontend::compile::PackageStore,
+        package_id: qsc_hir::hir::PackageId,
+        capabilities: RuntimeCapabilityFlags,
+    ) -> Result<PackageStoreComputeProperties, Vec<Error>> {
+        let fir_store = lower_store(package_store);
+        let fir_package_id = map_hir_package_to_fir(package_id);
+        Self::run_fir_passes_on_fir(&fir_store, fir_package_id, capabilities)
+    }
+
+    pub fn run_fir_passes_on_fir(
+        fir_store: &qsc_fir::fir::PackageStore,
+        package_id: qsc_fir::fir::PackageId,
+        capabilities: RuntimeCapabilityFlags,
+    ) -> Result<PackageStoreComputeProperties, Vec<Error>> {
+        run_rca_pass(fir_store, package_id, capabilities)
+    }
 }
 
 /// Run the default set of passes required for evaluation.
diff --git a/compiler/qsc_rca/Cargo.toml b/compiler/qsc_rca/Cargo.toml
index 5b45e4ad..0ff5ffcb 100644
--- a/compiler/qsc_rca/Cargo.toml
+++ b/compiler/qsc_rca/Cargo.toml
@@ -15,12 +15,12 @@ indenter = { workspace = true }
 qsc_data_structures = { path = "../qsc_data_structures" }
 qsc_fir = { path = "../qsc_fir" }
 qsc_frontend = { path = "../qsc_frontend" }
+qsc_lowerer = { path = "../qsc_lowerer" }
 rustc-hash = { workspace = true }
 
 [dev-dependencies]
 expect-test = { workspace = true }
 qsc = { path = "../qsc" }
-qsc_eval = { path = "../qsc_eval" }
 qsc_passes = { path = "../qsc_passes" }
 
 [lints]
diff --git a/compiler/qsc_rir/src/rir.rs b/compiler/qsc_rir/src/rir.rs
index 9640d11c..21e49c23 100644
--- a/compiler/qsc_rir/src/rir.rs
+++ b/compiler/qsc_rir/src/rir.rs
@@ -174,7 +174,7 @@ impl Display for Callable {
         indent = set_indentation(indent, 1);
         write!(indent, "\nname: {}", self.name)?;
         write!(indent, "\ncall_type: {}", self.call_type)?;
-        write!(indent, "\ninput_type: ")?;
+        write!(indent, "\ninput_type:")?;
         if self.input_type.is_empty() {
             write!(indent, " <VOID>")?;
         } else {
@@ -184,13 +184,13 @@ impl Display for Callable {
             }
             indent = set_indentation(indent, 1);
         }
-        write!(indent, "\noutput_type: ")?;
+        write!(indent, "\noutput_type:")?;
         if let Some(output_type) = &self.output_type {
             write!(indent, " {output_type}")?;
         } else {
             write!(indent, " <VOID>")?;
         }
-        write!(indent, "\nbody: ")?;
+        write!(indent, "\nbody:")?;
         if let Some(body_block_id) = self.body {
             write!(indent, " {}", body_block_id.0)?;
         } else {
diff --git a/language_service/Cargo.toml b/language_service/Cargo.toml
index 2765370c..6de48a17 100644
--- a/language_service/Cargo.toml
+++ b/language_service/Cargo.toml
@@ -16,15 +16,15 @@ serde = { workspace = true }
 serde_json = { workspace = true }
 
 [dependencies]
+async-trait = { workspace = true }
 futures = { workspace = true }
 futures-util = { workspace = true }
 log = { workspace = true }
 miette = { workspace = true }
 qsc = { path = "../compiler/qsc" }
-rustc-hash = { workspace = true }
 qsc_linter = { path = "../compiler/qsc_linter" }
 qsc_project = { path = "../compiler/qsc_project", features = ["async"] }
-async-trait = { workspace = true }
+rustc-hash = { workspace = true }
 
 [lints]
 workspace = true
diff --git a/language_service/src/compilation.rs b/language_service/src/compilation.rs
index db2739ef..a006ea0c 100644
--- a/language_service/src/compilation.rs
+++ b/language_service/src/compilation.rs
@@ -12,7 +12,7 @@ use qsc::{
     line_column::{Encoding, Position},
     resolve,
     target::Profile,
-    CompileUnit, LanguageFeatures, PackageStore, PackageType, SourceMap, Span,
+    CompileUnit, LanguageFeatures, PackageStore, PackageType, PassContext, SourceMap, Span,
 };
 use qsc_linter::LintConfig;
 use std::sync::Arc;
@@ -72,14 +72,38 @@ impl Compilation {
             language_features,
         );
 
-        let lints = qsc::linter::run_lints(&unit, Some(lints_config));
-        let mut lints = lints
-            .into_iter()
-            .map(|lint| WithSource::from_map(&unit.sources, qsc::compile::ErrorKind::Lint(lint)))
-            .collect();
-        errors.append(&mut lints);
-
         let package_id = package_store.insert(unit);
+        let unit = package_store
+            .get(package_id)
+            .expect("expected to find user package");
+
+        // baseprofchk will handle the case where the target profile is Base
+        if errors.is_empty()
+            && target_profile != Profile::Unrestricted
+            && target_profile != Profile::Base
+        {
+            let cap_results = PassContext::run_fir_passes_on_hir(
+                &package_store,
+                package_id,
+                target_profile.into(),
+            );
+            if let Err(caps_errors) = cap_results {
+                for err in caps_errors {
+                    errors.push(WithSource::from_map(
+                        &unit.sources,
+                        compile::ErrorKind::Pass(err),
+                    ));
+                }
+            }
+        }
+
+        let lints = qsc::linter::run_lints(unit, Some(lints_config));
+        for lint in lints {
+            errors.push(WithSource::from_map(
+                &unit.sources,
+                qsc::compile::ErrorKind::Lint(lint),
+            ));
+        }
 
         Self {
             package_store,
diff --git a/library/std/convert.qs b/library/std/convert.qs
index a2fa5923..f0dd3710 100644
--- a/library/std/convert.qs
+++ b/library/std/convert.qs
@@ -27,6 +27,7 @@ namespace Microsoft.Quantum.Convert {
     ///
     /// # Output
     /// A `Bool` representing the `input`.
+    @Config(Adaptive)
     @Config(Unrestricted)
     function ResultAsBool(input : Result) : Bool {
         input == One
@@ -42,6 +43,7 @@ namespace Microsoft.Quantum.Convert {
     ///
     /// # Output
     /// A `Result` representing the `input`.
+    @Config(Adaptive)
     @Config(Unrestricted)
     function BoolAsResult(input : Bool) : Result {
         if input { One } else { Zero }
@@ -168,6 +170,7 @@ namespace Microsoft.Quantum.Convert {
     /// // The following returns 1
     /// let int1 = ResultArrayAsInt([One,Zero])
     /// ```
+    @Config(Adaptive)
     @Config(Unrestricted)
     function ResultArrayAsInt(results : Result[]) : Int {
         let nBits = Length(results);
@@ -193,6 +196,7 @@ namespace Microsoft.Quantum.Convert {
     ///
     /// # Output
     /// A `Bool[]` representing the `input`.
+    @Config(Adaptive)
     @Config(Unrestricted)
     function ResultArrayAsBoolArray(input : Result[]) : Bool[] {
         mutable output = [];
@@ -213,6 +217,7 @@ namespace Microsoft.Quantum.Convert {
     ///
     /// # Output
     /// A `Result[]` representing the `input`.
+    @Config(Adaptive)
     @Config(Unrestricted)
     function BoolArrayAsResultArray(input : Bool[]) : Result[] {
         mutable output = [];
diff --git a/library/std/diagnostics.qs b/library/std/diagnostics.qs
index 669e1853..147adc33 100644
--- a/library/std/diagnostics.qs
+++ b/library/std/diagnostics.qs
@@ -69,11 +69,13 @@ namespace Microsoft.Quantum.Diagnostics {
         body intrinsic;
     }
 
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation CheckZero(qubit : Qubit) : Bool {
         body intrinsic;
     }
 
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation CheckAllZero(qubits : Qubit[]) : Bool {
         for q in qubits {
@@ -120,6 +122,7 @@ namespace Microsoft.Quantum.Diagnostics {
     /// Operation defining the expected behavior for the operation under test.
     /// # Output
     /// True if operations are equal, false otherwise.
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation CheckOperationsAreEqual(
         nQubits : Int,
diff --git a/library/std/internal.qs b/library/std/internal.qs
index f988b30e..35b79131 100644
--- a/library/std/internal.qs
+++ b/library/std/internal.qs
@@ -131,6 +131,7 @@ namespace Microsoft.Quantum.Intrinsic {
         }
     }
 
+    @Config(Adaptive)
     @Config(Unrestricted)
     internal operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
         body ... {
diff --git a/library/std/intrinsic.qs b/library/std/intrinsic.qs
index dfaaf397..e89a9a26 100644
--- a/library/std/intrinsic.qs
+++ b/library/std/intrinsic.qs
@@ -218,6 +218,7 @@ namespace Microsoft.Quantum.Intrinsic {
     /// ```qsharp
     /// Measure([PauliZ], [qubit]);
     /// ```
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation M(qubit : Qubit) : Result {
         __quantum__qis__m__body(qubit)
@@ -290,6 +291,7 @@ namespace Microsoft.Quantum.Intrinsic {
     ///
     /// If the basis array and qubit array are different lengths, then the
     /// operation will fail.
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation Measure(bases : Pauli[], qubits : Qubit[]) : Result {
         if Length(bases) != Length(qubits) {
diff --git a/library/std/measurement.qs b/library/std/measurement.qs
index d55a54f1..d23c6b18 100644
--- a/library/std/measurement.qs
+++ b/library/std/measurement.qs
@@ -146,6 +146,7 @@ namespace Microsoft.Quantum.Measurement {
     /// # Remarks
     /// This operation resets its input register to the |00...0> state,
     /// suitable for releasing back to a target machine.
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation MeasureInteger(target : Qubit[]) : Int {
         let nBits = Length(target);
diff --git a/library/std/random.qs b/library/std/random.qs
index f28f9e13..00509e97 100644
--- a/library/std/random.qs
+++ b/library/std/random.qs
@@ -24,6 +24,7 @@ namespace Microsoft.Quantum.Random {
     /// ```qsharp
     /// let roll = DrawRandomInt(1, 6);
     /// ```
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation DrawRandomInt(min : Int, max : Int) : Int {
         body intrinsic;
@@ -50,6 +51,7 @@ namespace Microsoft.Quantum.Random {
     /// ```qsharp
     /// let angle = DrawRandomDouble(0.0, 2.0 * PI());
     /// ```
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation DrawRandomDouble(min : Double, max : Double) : Double {
         body intrinsic;
diff --git a/library/std/re.qs b/library/std/re.qs
index 29b71bf1..3f0cdc2c 100644
--- a/library/std/re.qs
+++ b/library/std/re.qs
@@ -33,6 +33,7 @@ namespace Microsoft.Quantum.ResourceEstimation {
     /// needs to be executed in order to collect and cache estimates.
     /// `false` indicates if cached estimates have been incorporated into the overall costs
     /// and the code fragment should be skipped.
+    @Config(Adaptive)
     @Config(Unrestricted)
     function BeginEstimateCaching(name : String, variant : Int) : Bool {
         body intrinsic;
diff --git a/library/std/unstable_arithmetic_internal.qs b/library/std/unstable_arithmetic_internal.qs
index 317d7a04..31eda303 100644
--- a/library/std/unstable_arithmetic_internal.qs
+++ b/library/std/unstable_arithmetic_internal.qs
@@ -243,6 +243,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic {
     ///   Phys. Rev. A 87, 022328, 2013
     ///   [arXiv:1212.5069](https://arxiv.org/abs/1212.5069)
     ///   doi:10.1103/PhysRevA.87.022328
+    @Config(Adaptive)
     @Config(Unrestricted)
     internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
         // NOTE: Eventually this operation will be public and intrinsic.
diff --git a/library/std/unstable_table_lookup.qs b/library/std/unstable_table_lookup.qs
index 1d9d9b96..a3ee0622 100644
--- a/library/std/unstable_table_lookup.qs
+++ b/library/std/unstable_table_lookup.qs
@@ -43,6 +43,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup {
     ///     "Windowed arithmetic"
     /// [3] [arXiv:2211.01133](https://arxiv.org/abs/2211.01133)
     ///     "Space-time optimized table lookup"
+    @Config(Adaptive)
     @Config(Unrestricted)
     operation Select(
         data : Bool[][],
@@ -97,6 +98,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup {
         }
     }
 
+    @Config(Adaptive)
     @Config(Unrestricted)
     internal operation SinglyControlledSelect(
         ctl : Qubit,
@@ -166,6 +168,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup {
     /// # References
     /// - [arXiv:1905.07682](https://arxiv.org/abs/1905.07682)
     ///   "Windowed arithmetic"
+    @Config(Adaptive)
     @Config(Unrestricted)
     internal operation Unlookup(
         lookup : (Bool[][], Qubit[], Qubit[]) => Unit,
diff --git a/npm/qsharp/src/browser.ts b/npm/qsharp/src/browser.ts
index 16ebf9fe..7cc6f9af 100644
--- a/npm/qsharp/src/browser.ts
+++ b/npm/qsharp/src/browser.ts
@@ -170,7 +170,7 @@ export type {
   VSDiagnostic,
 } from "../lib/web/qsc_wasm.js";
 export { type Dump, type ShotResult } from "./compiler/common.js";
-export { type CompilerState } from "./compiler/compiler.js";
+export { type CompilerState, type ProgramConfig } from "./compiler/compiler.js";
 export { QscEventTarget } from "./compiler/events.js";
 export {
   getAllKatas,
diff --git a/npm/qsharp/src/compiler/compiler.ts b/npm/qsharp/src/compiler/compiler.ts
index 209a0102..f817350d 100644
--- a/npm/qsharp/src/compiler/compiler.ts
+++ b/npm/qsharp/src/compiler/compiler.ts
@@ -94,6 +94,8 @@ export type ProgramConfig = {
   sources: [string, string][];
   /** An array of language features to be opted in to in this compilation. */
   languageFeatures?: string[];
+  /** Target compilation profile. */
+  profile?: TargetProfile;
 };
 
 // WebWorker also support being explicitly terminated to tear down the worker thread
@@ -138,22 +140,24 @@ export class Compiler implements ICompiler {
     if (Array.isArray(sourcesOrConfig)) {
       return this.deprecatedGetQir(sourcesOrConfig, languageFeatures || []);
     } else {
-      return this.newGetQir(sourcesOrConfig);
+      const config = sourcesOrConfig as ProgramConfig;
+      return this.newGetQir(config);
     }
   }
 
   async newGetQir({
     sources,
     languageFeatures = [],
+    profile = "base",
   }: ProgramConfig): Promise<string> {
-    return this.wasm.get_qir(sources, languageFeatures);
+    return this.wasm.get_qir(sources, languageFeatures, profile);
   }
 
   async deprecatedGetQir(
     sources: [string, string][],
     languageFeatures: string[],
   ): Promise<string> {
-    return this.wasm.get_qir(sources, languageFeatures);
+    return this.wasm.get_qir(sources, languageFeatures, "base");
   }
 
   async getEstimates(
diff --git a/pip/qsharp/_native.pyi b/pip/qsharp/_native.pyi
index c8f19de0..8c5afcdf 100644
--- a/pip/qsharp/_native.pyi
+++ b/pip/qsharp/_native.pyi
@@ -12,9 +12,12 @@ class TargetProfile:
     The target profile is a description of a target's capabilities.
     """
 
-    Unrestricted: ClassVar[Any]
+    Adaptive: ClassVar[Any]
     """
-    Describes the unrestricted set of capabilities required to run any Q# program.
+    Target supports the core set of adaptive.
+
+    This option maps to the Adaptive Profile as defined by the QIR specification
+    without any extensions.
     """
 
     Base: ClassVar[Any]
@@ -25,6 +28,11 @@ class TargetProfile:
     This option maps to the Base Profile as defined by the QIR specification.
     """
 
+    Unrestricted: ClassVar[Any]
+    """
+    Describes the unrestricted set of capabilities required to run any Q# program.
+    """
+
 class Interpreter:
     """A Q# interpreter."""
 
diff --git a/pip/qsharp/_qsharp.py b/pip/qsharp/_qsharp.py
index c63bf66a..1cff0699 100644
--- a/pip/qsharp/_qsharp.py
+++ b/pip/qsharp/_qsharp.py
@@ -9,6 +9,7 @@ from ._native import (
     Output,
     Circuit,
 )
+from warnings import warn
 from typing import Any, Callable, Dict, Optional, TypedDict, Union, List
 from .estimator._estimator import EstimatorResult, EstimatorParams
 import json
@@ -23,10 +24,15 @@ class Config:
     """
 
     def __init__(self, target_profile: TargetProfile, language_features: List[str]):
-        if target_profile == TargetProfile.Unrestricted:
-            self._config = {"targetProfile": "unrestricted"}
+        if target_profile == TargetProfile.Adaptive:
+            self._config = {"targetProfile": "adaptive"}
+            warn("The adaptive target profile is a preview feature.")
+            warn("Functionality may be incomplete or incorrect.")
         elif target_profile == TargetProfile.Base:
             self._config = {"targetProfile": "base"}
+        elif target_profile == TargetProfile.Unrestricted:
+            self._config = {"targetProfile": "unrestricted"}
+
         self._config["languageFeatures"] = language_features
 
     def __repr__(self) -> str:
diff --git a/pip/src/interpreter.rs b/pip/src/interpreter.rs
index a269b072..17db39e9 100644
--- a/pip/src/interpreter.rs
+++ b/pip/src/interpreter.rs
@@ -51,14 +51,18 @@ fn _native(py: Python, m: &PyModule) -> PyResult<()> {
 /// A target profile describes the capabilities of the hardware or simulator
 /// which will be used to run the Q# program.
 pub(crate) enum TargetProfile {
-    /// Target supports the full set of capabilities required to run any Q# program.
+    /// Target supports the core set of adaptive.
     ///
-    /// This option maps to the Full Profile as defined by the QIR specification.
-    Unrestricted,
+    /// This option maps to the Adaptive Profile as defined by the QIR specification without any extensions.
+    Adaptive,
     /// Target supports the minimal set of capabilities required to run a quantum program.
     ///
     /// This option maps to the Base Profile as defined by the QIR specification.
     Base,
+    /// Target supports the full set of capabilities required to run any Q# program.
+    ///
+    /// This option maps to the Full Profile as defined by the QIR specification.
+    Unrestricted,
 }
 
 #[pyclass(unsendable)]
@@ -110,8 +114,9 @@ impl Interpreter {
         list_directory: Option<PyObject>,
     ) -> PyResult<Self> {
         let target = match target {
-            TargetProfile::Unrestricted => Profile::Unrestricted,
+            TargetProfile::Adaptive => Profile::Adaptive,
             TargetProfile::Base => Profile::Base,
+            TargetProfile::Unrestricted => Profile::Unrestricted,
         };
         let language_features = language_features.unwrap_or_default();
 
diff --git a/vscode/package.json b/vscode/package.json
index 77856d69..bd4281fe 100644
--- a/vscode/package.json
+++ b/vscode/package.json
@@ -101,11 +101,13 @@
           "default": "unrestricted",
           "enum": [
             "unrestricted",
-            "base"
+            "base",
+            "adaptive"
           ],
           "enumDescriptions": [
             "The set of all capabilities required to run any Q# program.",
-            "The minimal set of capabilities required to run a quantum program. This option maps to the Base Profile as defined by the QIR specification."
+            "The minimal set of capabilities required to run a quantum program. This option maps to the Base Profile as defined by the QIR specification.",
+            "The set of capabilities required to run an adaptive quantum program. This option maps to the Adaptive Profile as defined by the QIR specification."
           ],
           "description": "Setting the target profile allows the Q# extension to generate programs that are compatible with a specific target. The target is the hardware or simulator which will be used to run the Q# program. The target profile is a description of a target's capabilities."
         },
@@ -118,6 +120,16 @@
           "type": "boolean",
           "default": true,
           "description": "Enables the Circuit code lens to synthesize circuit diagrams for Q# programs and operations."
+        },
+        "Q#.enablePreviewQirGen": {
+          "type": "boolean",
+          "default": false,
+          "description": "Enables the preview QIR code generation functionality."
+        },
+        "Q#.enableAdaptiveProfile": {
+          "type": "boolean",
+          "default": false,
+          "description": "Enables Adaptive as a target profile."
         }
       }
     },
diff --git a/vscode/src/config.ts b/vscode/src/config.ts
index 879f51b2..6b65bdf7 100644
--- a/vscode/src/config.ts
+++ b/vscode/src/config.ts
@@ -9,6 +9,7 @@ export function getTarget(): TargetProfile {
     .getConfiguration("Q#")
     .get<TargetProfile>("targetProfile", "unrestricted");
   switch (target) {
+    case "adaptive":
     case "base":
     case "unrestricted":
       return target;
@@ -29,6 +30,8 @@ export async function setTarget(target: TargetProfile) {
 
 export function getTargetFriendlyName(targetProfile?: string) {
   switch (targetProfile) {
+    case "adaptive":
+      return "Q#: QIR adaptive";
     case "base":
       return "Q#: QIR base";
     case "unrestricted":
@@ -52,3 +55,17 @@ export function getShowCircuitCodeLens(): boolean {
     true, // The default value should be set in `package.json` as well.
   );
 }
+
+export function getEnablePreviewQirGen(): boolean {
+  return vscode.workspace.getConfiguration("Q#").get<boolean>(
+    "enablePreviewQirGen",
+    false, // The default value should be set in `package.json` as well.
+  );
+}
+
+export function getEnableAdaptiveProfile(): boolean {
+  return vscode.workspace.getConfiguration("Q#").get<boolean>(
+    "enableAdaptiveProfile",
+    false, // The default value should be set in `package.json` as well.
+  );
+}
diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts
index 291020f9..1338a76a 100644
--- a/vscode/src/extension.ts
+++ b/vscode/src/extension.ts
@@ -278,6 +278,7 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) {
   const targetProfile = getTarget();
 
   switch (targetProfile) {
+    case "adaptive":
     case "base":
     case "unrestricted":
       break;
diff --git a/vscode/src/qirGeneration.ts b/vscode/src/qirGeneration.ts
index c0bf6332..3ba1a039 100644
--- a/vscode/src/qirGeneration.ts
+++ b/vscode/src/qirGeneration.ts
@@ -2,11 +2,11 @@
 // Licensed under the MIT License.
 
 import * as vscode from "vscode";
-import { getCompilerWorker, log } from "qsharp-lang";
+import { getCompilerWorker, log, ProgramConfig } from "qsharp-lang";
 import { isQsharpDocument } from "./common";
 import { EventType, sendTelemetryEvent } from "./telemetry";
 import { getRandomGuid } from "./utils";
-import { getTarget, setTarget } from "./config";
+import { getTarget, getEnablePreviewQirGen, setTarget } from "./config";
 import { loadProject } from "./projectSystem";
 
 const generateQirTimeoutMs = 30000;
@@ -32,20 +32,24 @@ export async function getQirForActiveWindow(): Promise<string> {
 
   // Check that the current target is base profile, and current doc has no errors.
   const targetProfile = getTarget();
+  const enablePreviewQirGen = getEnablePreviewQirGen();
   if (targetProfile !== "base") {
-    const result = await vscode.window.showWarningMessage(
-      "Submitting to Azure is only supported when targeting the QIR base profile.",
-      { modal: true },
-      { title: "Change the QIR target profile and continue", action: "set" },
-      { title: "Cancel", action: "cancel", isCloseAffordance: true },
-    );
-    if (result?.action !== "set") {
-      throw new QirGenerationError(
-        "Submitting to Azure is only supported when targeting the QIR base profile. " +
-          "Please update the QIR target via the status bar selector or extension settings.",
+    const allowed = targetProfile === "adaptive" && enablePreviewQirGen;
+    if (!allowed) {
+      const result = await vscode.window.showWarningMessage(
+        "Submitting to Azure is only supported when targeting the QIR base profile.",
+        { modal: true },
+        { title: "Change the QIR target profile and continue", action: "set" },
+        { title: "Cancel", action: "cancel", isCloseAffordance: true },
       );
-    } else {
-      setTarget("base");
+      if (result?.action !== "set") {
+        throw new QirGenerationError(
+          "Submitting to Azure is only supported when targeting the QIR base profile. " +
+            "Please update the QIR target via the status bar selector or extension settings.",
+        );
+      } else {
+        setTarget("base");
+      }
     }
   }
   let sources: [string, string][] = [];
@@ -77,7 +81,16 @@ export async function getQirForActiveWindow(): Promise<string> {
     const associationId = getRandomGuid();
     const start = performance.now();
     sendTelemetryEvent(EventType.GenerateQirStart, { associationId }, {});
-    result = await worker.getQir(sources, languageFeatures);
+    if (enablePreviewQirGen) {
+      languageFeatures.push("preview-qir-gen");
+    }
+    const config = {
+      sources,
+      languageFeatures,
+      profile: getTarget(),
+    } as ProgramConfig;
+    result = await worker.getQir(config);
+
     sendTelemetryEvent(
       EventType.GenerateQirEnd,
       { associationId },
diff --git a/vscode/src/statusbar.ts b/vscode/src/statusbar.ts
index d362d6b0..f1feccc9 100644
--- a/vscode/src/statusbar.ts
+++ b/vscode/src/statusbar.ts
@@ -4,7 +4,12 @@
 import { log, TargetProfile } from "qsharp-lang";
 import * as vscode from "vscode";
 import { isQsharpDocument } from "./common";
-import { getTarget, getTargetFriendlyName, setTarget } from "./config";
+import {
+  getEnableAdaptiveProfile,
+  getTarget,
+  getTargetFriendlyName,
+  setTarget,
+} from "./config";
 
 export function activateTargetProfileStatusBarItem(): vscode.Disposable[] {
   const disposables = [];
@@ -81,7 +86,7 @@ function registerTargetProfileCommand() {
     "qsharp-vscode.setTargetProfile",
     async () => {
       const target = await vscode.window.showQuickPick(
-        targetProfiles.map((profile) => ({
+        getTargetProfiles().map((profile) => ({
           label: profile.uiText,
         })),
         { placeHolder: "Select the QIR target profile" },
@@ -95,12 +100,29 @@ function registerTargetProfileCommand() {
 }
 
 const targetProfiles = [
+  { configName: "adaptive", uiText: "Q#: QIR adaptive" },
   { configName: "base", uiText: "Q#: QIR base" },
   { configName: "unrestricted", uiText: "Q#: unrestricted" },
 ];
 
+function getTargetProfiles(): {
+  configName: string;
+  uiText: string;
+}[] {
+  const allow_adaptive = getEnableAdaptiveProfile();
+  if (allow_adaptive) {
+    return targetProfiles;
+  } else {
+    return targetProfiles.filter(
+      (profile) => profile.configName !== "adaptive",
+    );
+  }
+}
+
 function getTargetProfileSetting(uiText: string): TargetProfile {
   switch (uiText) {
+    case "Q#: QIR adaptive":
+      return "adaptive";
     case "Q#: QIR base":
       return "base";
     case "Q#: unrestricted":
diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs
index ea47c612..ee5a8313 100644
--- a/wasm/src/language_service.rs
+++ b/wasm/src/language_service.rs
@@ -489,7 +489,7 @@ serializable_type! {
         pub languageFeatures: Option<Vec<String>>
     },
     r#"export interface INotebookMetadata {
-        targetProfile?: "unrestricted" | "base";
+        targetProfile?: "adaptive" | "base" | "unrestricted";
         languageFeatures?: "v2-preview-syntax"[];
     }"#,
     INotebookMetadata
diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs
index 49c731f2..af3bd269 100644
--- a/wasm/src/lib.rs
+++ b/wasm/src/lib.rs
@@ -75,10 +75,17 @@ pub fn get_source_map(sources: Vec<js_sys::Array>, entry: &Option<String>) -> So
 pub fn get_qir(
     sources: Vec<js_sys::Array>,
     language_features: Vec<String>,
+    profile: &str,
 ) -> Result<String, String> {
     let language_features = LanguageFeatures::from_iter(language_features);
     let sources = get_source_map(sources, &None);
-    _get_qir(sources, language_features)
+    let profile =
+        Profile::from_str(profile).map_err(|()| format!("Invalid target profile {profile}"))?;
+    if language_features.contains(LanguageFeatures::PreviewQirGen) {
+        qsc::codegen::get_qir(sources, language_features, profile.into())
+    } else {
+        _get_qir(sources, language_features)
+    }
 }
 
 // allows testing without wasm bindings.
@@ -420,5 +427,5 @@ pub fn generate_docs() -> JsValue {
 
 #[wasm_bindgen(typescript_custom_section)]
 const TARGET_PROFILE: &'static str = r#"
-export type TargetProfile = "base" | "unrestricted";
+export type TargetProfile = "adaptive" | "base" | "unrestricted";
 "#;


Test patch:
diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs
index 8a7d654e..dc1ab6df 100644
--- a/compiler/qsc/src/interpret/tests.rs
+++ b/compiler/qsc/src/interpret/tests.rs
@@ -506,6 +506,74 @@ mod given_interpreter {
             is_only_value(&result, &output, &Value::unit());
         }
 
+        #[test]
+        fn callables_failing_profile_validation_are_still_registered() {
+            fn verify_same_error<E>(result: &Result<Value, Vec<E>>, output: &str)
+            where
+                E: Diagnostic,
+            {
+                is_only_error(
+                    result,
+                    output,
+                    &expect![[r#"
+                    cannot use a dynamic integer value
+                       [line_0] [set x = 2]
+                    cannot use a dynamic integer value
+                       [line_0] [x]
+                "#]],
+                );
+            }
+            let mut interpreter =
+                get_interpreter_with_capbilities(RuntimeCapabilityFlags::ForwardBranching);
+            let (result, output) = line(
+                &mut interpreter,
+                indoc! {r#"
+                    operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
+                "#},
+            );
+            verify_same_error(&result, &output);
+            // do something innocuous
+            let (result, output) = line(&mut interpreter, indoc! {r#"Foo()"#});
+            // if the callable wasn't registered, this would panic instead of returning an error.
+            verify_same_error(&result, &output);
+        }
+
+        #[test]
+        fn once_rca_validation_fails_following_calls_also_fail_by_design() {
+            fn verify_same_error<E>(result: &Result<Value, Vec<E>>, output: &str)
+            where
+                E: Diagnostic,
+            {
+                is_only_error(
+                    result,
+                    output,
+                    &expect![[r#"
+                    cannot use a dynamic integer value
+                       [line_0] [set x = 2]
+                    cannot use a dynamic integer value
+                       [line_0] [x]
+                "#]],
+                );
+            }
+            let mut interpreter =
+                get_interpreter_with_capbilities(RuntimeCapabilityFlags::ForwardBranching);
+            let (result, output) = line(
+                &mut interpreter,
+                indoc! {r#"
+                    operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
+                "#},
+            );
+            verify_same_error(&result, &output);
+            // do something innocuous
+            let (result, output) = line(
+                &mut interpreter,
+                indoc! {r#"
+                    let y = 7;
+                "#},
+            );
+            verify_same_error(&result, &output);
+        }
+
         #[test]
         fn namespace_usable_before_definition() {
             let mut interpreter = get_interpreter();
@@ -1102,6 +1170,17 @@ mod given_interpreter {
         .expect("interpreter should be created")
     }
 
+    fn get_interpreter_with_capbilities(capabilities: RuntimeCapabilityFlags) -> Interpreter {
+        Interpreter::new(
+            true,
+            SourceMap::default(),
+            PackageType::Lib,
+            capabilities,
+            LanguageFeatures::default(),
+        )
+        .expect("interpreter should be created")
+    }
+
     fn is_only_value(result: &InterpretResult, output: &str, value: &Value) {
         assert_eq!("", output);
 
diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs
index bf4ce916..8b3f4582 100644
--- a/compiler/qsc_eval/src/intrinsic/tests.rs
+++ b/compiler/qsc_eval/src/intrinsic/tests.rs
@@ -6,7 +6,6 @@
 use std::f64::consts;
 
 use crate::backend::{Backend, SparseSim};
-use crate::debug::map_hir_package_to_fir;
 use crate::tests::eval_graph;
 use crate::Env;
 use crate::{
@@ -20,6 +19,7 @@ use num_bigint::BigInt;
 use qsc_data_structures::language_features::LanguageFeatures;
 use qsc_fir::fir;
 use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::map_hir_package_to_fir;
 use qsc_passes::{run_core_passes, run_default_passes, PackageType};
 
 #[derive(Default)]
@@ -148,7 +148,7 @@ impl Backend for CustomSim {
 fn check_intrinsic(file: &str, expr: &str, out: &mut impl Receiver) -> Result<Value, Error> {
     let mut core = compile::core();
     run_core_passes(&mut core);
-    let core_fir = crate::lower::Lowerer::new().lower_package(&core.package);
+    let core_fir = qsc_lowerer::Lowerer::new().lower_package(&core.package);
     let mut store = PackageStore::new(core);
 
     let mut std = compile::std(&store, RuntimeCapabilityFlags::all());
@@ -160,7 +160,7 @@ fn check_intrinsic(file: &str, expr: &str, out: &mut impl Receiver) -> Result<Va
         RuntimeCapabilityFlags::all()
     )
     .is_empty());
-    let std_fir = crate::lower::Lowerer::new().lower_package(&std.package);
+    let std_fir = qsc_lowerer::Lowerer::new().lower_package(&std.package);
     let std_id = store.insert(std);
 
     let sources = SourceMap::new([("test".into(), file.into())], Some(expr.into()));
@@ -179,7 +179,7 @@ fn check_intrinsic(file: &str, expr: &str, out: &mut impl Receiver) -> Result<Va
         RuntimeCapabilityFlags::all()
     )
     .is_empty());
-    let unit_fir = crate::lower::Lowerer::new().lower_package(&unit.package);
+    let unit_fir = qsc_lowerer::Lowerer::new().lower_package(&unit.package);
     let entry = unit_fir.entry_exec_graph.clone();
 
     let id = store.insert(unit);
diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs
index 9a3dc44e..1fc6f67a 100644
--- a/compiler/qsc_eval/src/tests.rs
+++ b/compiler/qsc_eval/src/tests.rs
@@ -8,7 +8,7 @@ use std::rc::Rc;
 
 use crate::{
     backend::{Backend, SparseSim},
-    debug::{map_hir_package_to_fir, Frame},
+    debug::Frame,
     exec_graph_section,
     output::{GenericReceiver, Receiver},
     val, Env, Error, State, StepAction, StepResult, Value,
@@ -19,6 +19,7 @@ use qsc_data_structures::language_features::LanguageFeatures;
 use qsc_fir::fir::{self, ExecGraphNode, StmtId};
 use qsc_fir::fir::{PackageId, PackageStoreLookup};
 use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::map_hir_package_to_fir;
 use qsc_passes::{run_core_passes, run_default_passes, PackageType};
 
 /// Evaluates the given control flow graph with the given context.
@@ -43,7 +44,7 @@ pub(super) fn eval_graph(
 }
 
 fn check_expr(file: &str, expr: &str, expect: &Expect) {
-    let mut fir_lowerer = crate::lower::Lowerer::new();
+    let mut fir_lowerer = qsc_lowerer::Lowerer::new();
     let mut core = compile::core();
     run_core_passes(&mut core);
     let core_fir = fir_lowerer.lower_package(&core.package);
@@ -112,7 +113,7 @@ fn check_partial_eval_stmt(
 ) {
     let mut core = compile::core();
     run_core_passes(&mut core);
-    let core_fir = crate::lower::Lowerer::new().lower_package(&core.package);
+    let core_fir = qsc_lowerer::Lowerer::new().lower_package(&core.package);
     let mut store = PackageStore::new(core);
 
     let mut std = compile::std(&store, RuntimeCapabilityFlags::all());
@@ -124,7 +125,7 @@ fn check_partial_eval_stmt(
         RuntimeCapabilityFlags::all()
     )
     .is_empty());
-    let std_fir = crate::lower::Lowerer::new().lower_package(&std.package);
+    let std_fir = qsc_lowerer::Lowerer::new().lower_package(&std.package);
     let std_id = store.insert(std);
 
     let sources = SourceMap::new([("test".into(), file.into())], Some(expr.into()));
@@ -143,7 +144,7 @@ fn check_partial_eval_stmt(
         RuntimeCapabilityFlags::all(),
     );
     assert!(pass_errors.is_empty(), "{pass_errors:?}");
-    let unit_fir = crate::lower::Lowerer::new().lower_package(&unit.package);
+    let unit_fir = qsc_lowerer::Lowerer::new().lower_package(&unit.package);
     fir_expect.assert_eq(&unit_fir.to_string());
 
     let entry = unit_fir.entry_exec_graph.clone();
diff --git a/compiler/qsc_partial_eval/src/tests.rs b/compiler/qsc_partial_eval/src/tests.rs
index ccf820bd..235cd4d7 100644
--- a/compiler/qsc_partial_eval/src/tests.rs
+++ b/compiler/qsc_partial_eval/src/tests.rs
@@ -8,9 +8,10 @@ use expect_test::{expect, Expect};
 use indoc::indoc;
 use qsc::{incremental::Compiler, PackageType};
 use qsc_data_structures::language_features::LanguageFeatures;
-use qsc_eval::{debug::map_hir_package_to_fir, lower::Lowerer};
 use qsc_fir::fir::{PackageId, PackageStore};
 use qsc_frontend::compile::{PackageStore as HirPackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::map_hir_package_to_fir;
+use qsc_lowerer::Lowerer;
 use qsc_rca::{Analyzer, PackageStoreComputeProperties};
 
 #[test]
@@ -29,9 +30,9 @@ fn empty_entry_point() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                 blocks:
                     Block 0: Block:
                         Return
@@ -62,9 +63,9 @@ fn allocate_one_qubit() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                 blocks:
                     Block 0: Block:
                         Return
@@ -96,16 +97,16 @@ fn call_to_single_qubit_operation() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                     Callable 1: Callable:
                         name: __quantum__qis__h__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                 blocks:
                     Block 0: Block:
                         Call id(1), args( Qubit(0), )
@@ -144,30 +145,30 @@ fn call_to_many_single_qubit_operations() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                     Callable 1: Callable:
                         name: __quantum__qis__h__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                     Callable 2: Callable:
                         name: __quantum__qis__x__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                     Callable 3: Callable:
                         name: __quantum__qis__y__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                 blocks:
                     Block 0: Block:
                         Call id(1), args( Qubit(0), )
@@ -203,17 +204,17 @@ fn call_to_rotation_operation_using_literal() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                     Callable 1: Callable:
                         name: __quantum__qis__rx__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Double
                             [1]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                 blocks:
                     Block 0: Block:
                         Call id(1), args( Double(1), Qubit(0), )
@@ -248,17 +249,17 @@ fn calls_to_rotation_operation_using_inline_expressions() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                     Callable 1: Callable:
                         name: __quantum__qis__ry__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Double
                             [1]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                 blocks:
                     Block 0: Block:
                         Call id(1), args( Double(0), Qubit(0), )
@@ -298,17 +299,17 @@ fn calls_to_rotation_operation_using_variables() {
                     Callable 0: Callable:
                         name: main
                         call_type: Regular
-                        input_type:  <VOID>
-                        output_type:  <VOID>
-                        body:  0
+                        input_type: <VOID>
+                        output_type: <VOID>
+                        body: 0
                     Callable 1: Callable:
                         name: __quantum__qis__rz__body
                         call_type: Regular
-                        input_type: 
+                        input_type:
                             [0]: Double
                             [1]: Qubit
-                        output_type:  <VOID>
-                        body:  <NONE>
+                        output_type: <VOID>
+                        body: <NONE>
                 blocks:
                     Block 0: Block:
                         Call id(1), args( Double(2), Qubit(0), )
diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs
index 2753faf5..1a4d10bb 100644
--- a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs
+++ b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs
@@ -5,9 +5,9 @@
 
 use super::tests_common::{
     check, CALL_DYNAMIC_FUNCTION, CALL_DYNAMIC_OPERATION,
-    CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
+    CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
     LOOP_WITH_DYNAMIC_CONDITION, MEASUREMENT_WITHIN_DYNAMIC_SCOPE, MINIMAL,
     RETURN_WITHIN_DYNAMIC_SCOPE, USE_CLOSURE_FUNCTION, USE_DYNAMICALLY_SIZED_ARRAY,
     USE_DYNAMIC_BIG_INT, USE_DYNAMIC_BOOLEAN, USE_DYNAMIC_DOUBLE, USE_DYNAMIC_FUNCTION,
@@ -267,7 +267,7 @@ fn use_of_dynamic_operation_yields_errors() {
 #[test]
 fn call_cyclic_function_with_classical_argument_yields_no_errors() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             []
         "#]],
@@ -277,7 +277,7 @@ fn call_cyclic_function_with_classical_argument_yields_no_errors() {
 #[test]
 fn call_cyclic_function_with_dynamic_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 UseOfDynamicInt(
@@ -300,7 +300,7 @@ fn call_cyclic_function_with_dynamic_argument_yields_errors() {
 #[test]
 fn call_cyclic_operation_with_classical_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
@@ -329,7 +329,7 @@ fn call_cyclic_operation_with_classical_argument_yields_errors() {
 #[test]
 fn call_cyclic_operation_with_dynamic_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs
index 5a6dd28d..927c7a89 100644
--- a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs
+++ b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs
@@ -7,9 +7,9 @@ use crate::capabilitiesck::tests_common::USE_DYNAMIC_RANGE;
 
 use super::tests_common::{
     check, CALL_DYNAMIC_FUNCTION, CALL_DYNAMIC_OPERATION,
-    CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
+    CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
     LOOP_WITH_DYNAMIC_CONDITION, MEASUREMENT_WITHIN_DYNAMIC_SCOPE, MINIMAL,
     RETURN_WITHIN_DYNAMIC_SCOPE, USE_CLOSURE_FUNCTION, USE_DYNAMICALLY_SIZED_ARRAY,
     USE_DYNAMIC_BIG_INT, USE_DYNAMIC_BOOLEAN, USE_DYNAMIC_DOUBLE, USE_DYNAMIC_FUNCTION,
@@ -222,7 +222,7 @@ fn use_of_dynamic_operation_yields_errors() {
 #[test]
 fn call_cyclic_function_with_classical_argument_yields_no_errors() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             []
         "#]],
@@ -232,7 +232,7 @@ fn call_cyclic_function_with_classical_argument_yields_no_errors() {
 #[test]
 fn call_cyclic_function_with_dynamic_argument_yields_error() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 CallToCyclicFunctionWithDynamicArg(
@@ -249,7 +249,7 @@ fn call_cyclic_function_with_dynamic_argument_yields_error() {
 #[test]
 fn call_cyclic_operation_with_classical_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
@@ -272,7 +272,7 @@ fn call_cyclic_operation_with_classical_argument_yields_errors() {
 #[test]
 fn call_cyclic_operation_with_dynamic_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_base.rs b/compiler/qsc_passes/src/capabilitiesck/tests_base.rs
index c022bbdb..7126376f 100644
--- a/compiler/qsc_passes/src/capabilitiesck/tests_base.rs
+++ b/compiler/qsc_passes/src/capabilitiesck/tests_base.rs
@@ -5,9 +5,9 @@
 
 use super::tests_common::{
     check, CALL_DYNAMIC_FUNCTION, CALL_DYNAMIC_OPERATION,
-    CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
-    CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
+    CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+    CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION,
     LOOP_WITH_DYNAMIC_CONDITION, MEASUREMENT_WITHIN_DYNAMIC_SCOPE, MINIMAL,
     RETURN_WITHIN_DYNAMIC_SCOPE, USE_CLOSURE_FUNCTION, USE_DYNAMICALLY_SIZED_ARRAY,
     USE_DYNAMIC_BIG_INT, USE_DYNAMIC_BOOLEAN, USE_DYNAMIC_DOUBLE, USE_DYNAMIC_FUNCTION,
@@ -331,7 +331,7 @@ fn use_of_dynamic_operation_yields_errors() {
 #[test]
 fn call_cyclic_function_with_classical_argument_yields_no_errors() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             []
         "#]],
@@ -341,7 +341,7 @@ fn call_cyclic_function_with_classical_argument_yields_no_errors() {
 #[test]
 fn call_cyclic_function_with_dynamic_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 UseOfDynamicBool(
@@ -370,7 +370,7 @@ fn call_cyclic_function_with_dynamic_argument_yields_errors() {
 #[test]
 fn call_cyclic_operation_with_classical_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
@@ -399,7 +399,7 @@ fn call_cyclic_operation_with_classical_argument_yields_errors() {
 #[test]
 fn call_cyclic_operation_with_dynamic_argument_yields_errors() {
     check_profile(
-        CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT,
+        CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT,
         &expect![[r#"
             [
                 CyclicOperationSpec(
diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_common.rs b/compiler/qsc_passes/src/capabilitiesck/tests_common.rs
index 8e31c6ef..9c91f954 100644
--- a/compiler/qsc_passes/src/capabilitiesck/tests_common.rs
+++ b/compiler/qsc_passes/src/capabilitiesck/tests_common.rs
@@ -8,9 +8,9 @@ use expect_test::Expect;
 use crate::capabilitiesck::check_supported_capabilities;
 use qsc::{incremental::Compiler, PackageType};
 use qsc_data_structures::language_features::LanguageFeatures;
-use qsc_eval::{debug::map_hir_package_to_fir, lower::Lowerer};
 use qsc_fir::fir::{Package, PackageId, PackageStore};
 use qsc_frontend::compile::{PackageStore as HirPackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::{map_hir_package_to_fir, Lowerer};
 use qsc_rca::{Analyzer, PackageComputeProperties, PackageStoreComputeProperties};
 
 pub fn check(source: &str, expect: &Expect, capabilities: RuntimeCapabilityFlags) {
@@ -196,7 +196,7 @@ pub const USE_DYNAMIC_OPERATION: &str = r#"
         }
     }"#;
 
-pub const CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT: &str = r#"
+pub const CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT: &str = r#"
     function GaussSum(n : Int) : Int {
         if n == 0 {
             0
@@ -208,7 +208,7 @@ pub const CALL_TO_CICLYC_FUNCTION_WITH_CLASSICAL_ARGUMENT: &str = r#"
         let sum = GaussSum(10);
     }"#;
 
-pub const CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT: &str = r#"
+pub const CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT: &str = r#"
     function GaussSum(n : Int) : Int {
         if n == 0 {
             0
@@ -221,7 +221,7 @@ pub const CALL_TO_CICLYC_FUNCTION_WITH_DYNAMIC_ARGUMENT: &str = r#"
         let sum = GaussSum(M(q) == Zero ? 10 | 20);
     }"#;
 
-pub const CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT: &str = r#"
+pub const CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT: &str = r#"
     operation GaussSum(n : Int) : Int {
         if n == 0 {
             0
@@ -233,7 +233,7 @@ pub const CALL_TO_CICLYC_OPERATION_WITH_CLASSICAL_ARGUMENT: &str = r#"
         let sum = GaussSum(10);
     }"#;
 
-pub const CALL_TO_CICLYC_OPERATION_WITH_DYNAMIC_ARGUMENT: &str = r#"
+pub const CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT: &str = r#"
     operation GaussSum(n : Int) : Int {
         if n == 0 {
             0
diff --git a/compiler/qsc_rca/tests/test_utils.rs b/compiler/qsc_rca/tests/test_utils.rs
index 55bb8aaf..9e5c7c2d 100644
--- a/compiler/qsc_rca/tests/test_utils.rs
+++ b/compiler/qsc_rca/tests/test_utils.rs
@@ -4,9 +4,9 @@
 use expect_test::Expect;
 use qsc::incremental::Compiler;
 use qsc_data_structures::language_features::LanguageFeatures;
-use qsc_eval::{debug::map_hir_package_to_fir, lower::Lowerer};
 use qsc_fir::fir::{ItemKind, LocalItemId, Package, PackageStore, StoreItemId};
 use qsc_frontend::compile::{PackageStore as HirPackageStore, RuntimeCapabilityFlags, SourceMap};
+use qsc_lowerer::{map_hir_package_to_fir, Lowerer};
 use qsc_passes::PackageType;
 use qsc_rca::{Analyzer, ComputePropertiesLookup, PackageStoreComputeProperties};
 
diff --git a/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs b/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs
index 5c217bd6..7e16ca1f 100644
--- a/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs
+++ b/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs
@@ -43,9 +43,9 @@ fn remap_block_ids_no_changes() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Jump(1)
@@ -68,9 +68,9 @@ fn remap_block_ids_no_changes() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Jump(1)
@@ -117,9 +117,9 @@ fn remap_block_ids_out_of_order_no_branches() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  5
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 5
             blocks:
                 Block 3: Block:
                     Jump(7)
@@ -142,9 +142,9 @@ fn remap_block_ids_out_of_order_no_branches() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Jump(1)
@@ -202,9 +202,9 @@ fn remap_block_ids_out_of_order_with_one_branch() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  2
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 2
             blocks:
                 Block 0: Block:
                     Return
@@ -230,9 +230,9 @@ fn remap_block_ids_out_of_order_with_one_branch() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Branch Variable(0, Boolean), 1, 2
@@ -289,9 +289,9 @@ fn remap_block_ids_simple_loop() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  4
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 4
             blocks:
                 Block 2: Block:
                     Return
@@ -315,9 +315,9 @@ fn remap_block_ids_simple_loop() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Branch Variable(0, Boolean), 1, 2
@@ -361,9 +361,9 @@ fn remap_block_ids_infinite_loop() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  4
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 4
             blocks:
                 Block 0: Block:
                     Jump(4)
@@ -385,9 +385,9 @@ fn remap_block_ids_infinite_loop() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Jump(1)
@@ -448,9 +448,9 @@ fn remap_block_ids_nested_branching_loops() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  4
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 4
             blocks:
                 Block 2: Block:
                     Return
@@ -474,9 +474,9 @@ fn remap_block_ids_nested_branching_loops() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Branch Variable(0, Boolean), 1, 2
@@ -566,9 +566,9 @@ fn remap_block_ids_ensures_acyclic_program_gets_topological_ordering() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  4
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 4
             blocks:
                 Block 0: Block:
                     Jump(8)
@@ -604,9 +604,9 @@ fn remap_block_ids_ensures_acyclic_program_gets_topological_ordering() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
             blocks:
                 Block 0: Block:
                     Branch Variable(0, Boolean), 1, 2
diff --git a/compiler/qsc_rir/src/passes/ssa_transform/tests.rs b/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
index 2ac970bc..41f3e1a0 100644
--- a/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
+++ b/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
@@ -103,15 +103,15 @@ fn ssa_transform_removes_store_in_single_block_program() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -134,15 +134,15 @@ fn ssa_transform_removes_store_in_single_block_program() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -253,15 +253,15 @@ fn ssa_transform_removes_multiple_stores_in_single_block_program() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -288,15 +288,15 @@ fn ssa_transform_removes_multiple_stores_in_single_block_program() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -414,15 +414,15 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -453,15 +453,15 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -560,15 +560,15 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks_without_i
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -597,15 +597,15 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks_without_i
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -747,15 +747,15 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -788,15 +788,15 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -917,15 +917,15 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -956,15 +956,15 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1156,15 +1156,15 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1207,15 +1207,15 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1388,15 +1388,15 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1431,15 +1431,15 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1696,15 +1696,15 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1753,15 +1753,15 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -1993,15 +1993,15 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
@@ -2045,15 +2045,15 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() {
                 Callable 0: Callable:
                     name: main
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  <VOID>
-                    body:  0
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
                 Callable 1: Callable:
                     name: dynamic_bool
                     call_type: Regular
-                    input_type:  <VOID>
-                    output_type:  Boolean
-                    body:  <NONE>
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
             blocks:
                 Block 0: Block:
                     Variable(0, Boolean) = Call id(1), args( )
diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py
index f716651d..66d322ec 100644
--- a/pip/tests/test_interpreter.py
+++ b/pip/tests/test_interpreter.py
@@ -272,6 +272,76 @@ def test_entry_expr_circuit() -> None:
     )
 
 
+# this is by design
+def test_callables_failing_profile_validation_are_still_registered() -> None:
+    e = Interpreter(TargetProfile.Adaptive)
+    with pytest.raises(Exception) as excinfo:
+        e.interpret(
+            "operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }"
+        )
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+    with pytest.raises(Exception) as excinfo:
+        e.interpret("Foo()")
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+
+
+# this is by design
+def test_once_rca_validation_fails_following_calls_also_fail() -> None:
+    e = Interpreter(TargetProfile.Adaptive)
+    with pytest.raises(Exception) as excinfo:
+        e.interpret(
+            "operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }"
+        )
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+    with pytest.raises(Exception) as excinfo:
+        e.interpret("let x = 5;")
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+
+
+def test_adaptive_errors_are_raised_when_interpreting() -> None:
+    e = Interpreter(TargetProfile.Adaptive)
+    with pytest.raises(Exception) as excinfo:
+        e.interpret(
+            "operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }"
+        )
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+
+
+def test_adaptive_errors_are_raised_from_entry_expr() -> None:
+    e = Interpreter(TargetProfile.Adaptive)
+    e.interpret("use q = Qubit();")
+    with pytest.raises(Exception) as excinfo:
+        e.run("{mutable x = 1; if MResetZ(q) == One { set x = 2; }}")
+    assert "Qsc.CapabilitiesCk.UseOfDynamicInt" in str(excinfo)
+
+
+# This is temporary but asserts that the functionality is
+# Not yet implemented.
+def test_adaptive_qir_cannot_be_generated() -> None:
+    adaptive_input = """
+        namespace Test {
+            open Microsoft.Quantum.Math;
+            open QIR.Intrinsic;
+            @EntryPoint()
+            operation Main() : Unit {
+                use q = Qubit();
+                let pi_over_two = 4.0 / 2.0;
+                __quantum__qis__rz__body(pi_over_two, q);
+                mutable some_angle = ArcSin(0.0);
+                __quantum__qis__rz__body(some_angle, q);
+                set some_angle = ArcCos(-1.0) / PI();
+                __quantum__qis__rz__body(some_angle, q);
+            }
+        }
+        """
+    e = Interpreter(TargetProfile.Adaptive)
+    e.interpret(adaptive_input)
+    with pytest.raises(Exception) as excinfo:
+        e.qir("Test.Main()")
+
+    assert "UnsupportedRuntimeCapabilities" in str(excinfo)
+
+
 def test_operation_circuit() -> None:
     e = Interpreter(TargetProfile.Unrestricted)
     e.interpret("operation Foo(q: Qubit) : Result { H(q); return M(q) }")