Repository: microsoft/qsharp
Pull request #888 (2023-12-05 22:39:14)

Update UI to use profiles, compiler to use capabilities.
The capabilities are pulled from Cesar's spike PR trying to lay the integration point so that we have the compiler only ever works with capabilities. The profiles are currently defined in `qsc` so that the compiler can't take a dependency on profiles.

I'm not sure how many capabilities we'll need to map, so the flags enum may need to change to `u64` or a bit array.

Still not sure what to call the values in the `@Config()` attribute. Currently `Base`/`Full` are used. `None`/`Any` has been proposed.

Effects #863 
Replaces #842 


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 4be921e3..cb9c46cf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -892,6 +892,7 @@ dependencies = [
 name = "qsc_frontend"
 version = "0.0.0"
 dependencies = [
+ "bitflags 2.4.1",
  "enum-iterator",
  "expect-test",
  "indoc",
diff --git a/Cargo.toml b/Cargo.toml
index 1e694441..757e9e2a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ license = "MIT"
 version = "0.0.0"
 
 [workspace.dependencies]
+bitflags = "2.4.1"
 clap = "4.4"
 criterion = { version = "0.5", default-features = false }
 enum-iterator = "1.4"
diff --git a/build.py b/build.py
index 888e6f58..d11ad5d2 100755
--- a/build.py
+++ b/build.py
@@ -281,10 +281,8 @@ if build_pip:
 if build_widgets:
     step_start("Building the Python widgets")
 
-    python_cmd = "python.exe" if platform.system() == "Windows" else "python"
-
     widgets_build_args = [
-        python_cmd,
+        sys.executable,
         "-m",
         "pip",
         "wheel",
diff --git a/compiler/qsc/benches/eval.rs b/compiler/qsc/benches/eval.rs
index 6d845fad..9423da38 100644
--- a/compiler/qsc/benches/eval.rs
+++ b/compiler/qsc/benches/eval.rs
@@ -3,9 +3,9 @@
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use indoc::indoc;
-use qsc::{interpret::stateful, PackageType, TargetProfile};
+use qsc::{interpret::stateful, PackageType};
 use qsc_eval::output::GenericReceiver;
-use qsc_frontend::compile::SourceMap;
+use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceMap};
 
 const TELEPORT: &str = include_str!("../../../samples/algorithms/Teleportation.qs");
 const DEUTSCHJOZSA: &str = include_str!("../../../samples/algorithms/DeutschJozsa.qs");
@@ -14,9 +14,13 @@ const LARGE: &str = include_str!("./large.qs");
 pub fn teleport(c: &mut Criterion) {
     c.bench_function("Teleport evaluation", |b| {
         let sources = SourceMap::new([("Teleportation.qs".into(), TELEPORT.into())], None);
-        let mut evaluator =
-            stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                .expect("code should compile");
+        let mut evaluator = stateful::Interpreter::new(
+            true,
+            sources,
+            PackageType::Exe,
+            RuntimeCapabilityFlags::all(),
+        )
+        .expect("code should compile");
         b.iter(move || {
             let mut out = Vec::new();
             let mut rec = GenericReceiver::new(&mut out);
@@ -28,9 +32,13 @@ pub fn teleport(c: &mut Criterion) {
 pub fn deutsch_jozsa(c: &mut Criterion) {
     c.bench_function("Deutsch-Jozsa evaluation", |b| {
         let sources = SourceMap::new([("DeutschJozsa.qs".into(), DEUTSCHJOZSA.into())], None);
-        let mut evaluator =
-            stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                .expect("code should compile");
+        let mut evaluator = stateful::Interpreter::new(
+            true,
+            sources,
+            PackageType::Exe,
+            RuntimeCapabilityFlags::all(),
+        )
+        .expect("code should compile");
         b.iter(move || {
             let mut out = Vec::new();
             let mut rec = GenericReceiver::new(&mut out);
@@ -42,9 +50,13 @@ pub fn deutsch_jozsa(c: &mut Criterion) {
 pub fn large_file(c: &mut Criterion) {
     c.bench_function("Large file parity evaluation", |b| {
         let sources = SourceMap::new([("large.qs".into(), LARGE.into())], None);
-        let mut evaluator =
-            stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                .expect("code should compile");
+        let mut evaluator = stateful::Interpreter::new(
+            true,
+            sources,
+            PackageType::Exe,
+            RuntimeCapabilityFlags::all(),
+        )
+        .expect("code should compile");
         b.iter(move || {
             let mut out = Vec::new();
             let mut rec = GenericReceiver::new(&mut out);
@@ -68,9 +80,13 @@ pub fn array_append(c: &mut Criterion) {
                 .into(),
             ),
         );
-        let mut evaluator =
-            stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                .expect("code should compile");
+        let mut evaluator = stateful::Interpreter::new(
+            true,
+            sources,
+            PackageType::Exe,
+            RuntimeCapabilityFlags::all(),
+        )
+        .expect("code should compile");
         b.iter(move || {
             let mut out = Vec::new();
             let mut rec = GenericReceiver::new(&mut out);
@@ -94,9 +110,13 @@ pub fn array_update(c: &mut Criterion) {
                 .into(),
             ),
         );
-        let mut evaluator =
-            stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                .expect("code should compile");
+        let mut evaluator = stateful::Interpreter::new(
+            true,
+            sources,
+            PackageType::Exe,
+            RuntimeCapabilityFlags::all(),
+        )
+        .expect("code should compile");
         b.iter(move || {
             let mut out = Vec::new();
             let mut rec = GenericReceiver::new(&mut out);
diff --git a/compiler/qsc/benches/large.rs b/compiler/qsc/benches/large.rs
index 5a76204d..f58c4709 100644
--- a/compiler/qsc/benches/large.rs
+++ b/compiler/qsc/benches/large.rs
@@ -3,7 +3,7 @@
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile::{self, compile};
-use qsc_frontend::compile::{PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_passes::PackageType;
 
 const INPUT: &str = include_str!("./large.qs");
@@ -12,14 +12,14 @@ pub fn large_file(c: &mut Criterion) {
     c.bench_function("Large input file", |b| {
         b.iter(|| {
             let mut store = PackageStore::new(compile::core());
-            let std = store.insert(compile::std(&store, TargetProfile::Full));
+            let std = store.insert(compile::std(&store, RuntimeCapabilityFlags::all()));
             let sources = SourceMap::new([("large.qs".into(), INPUT.into())], None);
             let (_, reports) = compile(
                 &store,
                 &[std],
                 sources,
                 PackageType::Exe,
-                TargetProfile::Full,
+                RuntimeCapabilityFlags::all(),
             );
             assert!(reports.is_empty());
         })
diff --git a/compiler/qsc/benches/library.rs b/compiler/qsc/benches/library.rs
index 4607ea67..efebaabe 100644
--- a/compiler/qsc/benches/library.rs
+++ b/compiler/qsc/benches/library.rs
@@ -3,12 +3,12 @@
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile;
-use qsc_frontend::compile::{PackageStore, TargetProfile};
+use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags};
 
 pub fn library(c: &mut Criterion) {
     let store = PackageStore::new(compile::core());
     c.bench_function("Standard library", |b| {
-        b.iter(|| compile::std(&store, TargetProfile::Full))
+        b.iter(|| compile::std(&store, RuntimeCapabilityFlags::all()))
     });
 }
 
diff --git a/compiler/qsc/src/bin/qsc.rs b/compiler/qsc/src/bin/qsc.rs
index e6227660..87fc911e 100644
--- a/compiler/qsc/src/bin/qsc.rs
+++ b/compiler/qsc/src/bin/qsc.rs
@@ -10,7 +10,7 @@ use miette::{Context, IntoDiagnostic, Report};
 use qsc::compile::compile;
 use qsc_codegen::qir_base;
 use qsc_frontend::{
-    compile::{PackageStore, SourceContents, SourceMap, SourceName, TargetProfile},
+    compile::{PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName},
     error::WithSource,
 };
 use qsc_hir::hir::{Package, PackageId};
@@ -65,14 +65,14 @@ fn main() -> miette::Result<ExitCode> {
     let mut store = PackageStore::new(qsc::compile::core());
     let mut dependencies = Vec::new();
 
-    let (package_type, target) = if cli.emit.contains(&Emit::Qir) {
-        (PackageType::Exe, TargetProfile::Base)
+    let (package_type, capabilities) = if cli.emit.contains(&Emit::Qir) {
+        (PackageType::Exe, RuntimeCapabilityFlags::empty())
     } else {
-        (PackageType::Lib, TargetProfile::Full)
+        (PackageType::Lib, RuntimeCapabilityFlags::all())
     };
 
     if !cli.nostdlib {
-        dependencies.push(store.insert(qsc::compile::std(&store, target)));
+        dependencies.push(store.insert(qsc::compile::std(&store, capabilities)));
     }
 
     let mut sources = cli
@@ -94,7 +94,7 @@ fn main() -> miette::Result<ExitCode> {
 
     let entry = cli.entry.unwrap_or_default();
     let sources = SourceMap::new(sources, Some(entry.into()));
-    let (unit, errors) = compile(&store, &dependencies, sources, package_type, target);
+    let (unit, errors) = compile(&store, &dependencies, sources, package_type, capabilities);
     let package_id = store.insert(unit);
     let unit = store.get(package_id).expect("package should be in store");
 
diff --git a/compiler/qsc/src/bin/qsi.rs b/compiler/qsc/src/bin/qsi.rs
index 370370a4..323043fb 100644
--- a/compiler/qsc/src/bin/qsi.rs
+++ b/compiler/qsc/src/bin/qsi.rs
@@ -8,15 +8,12 @@ use clap::{crate_version, Parser};
 use miette::{Context, IntoDiagnostic, Report, Result};
 use num_bigint::BigUint;
 use num_complex::Complex64;
-use qsc::{
-    interpret::stateful::{self, InterpretResult, Interpreter},
-    TargetProfile,
-};
+use qsc::interpret::stateful::{self, InterpretResult, Interpreter};
 use qsc_eval::{
     output::{self, Receiver},
     val::Value,
 };
-use qsc_frontend::compile::{SourceContents, SourceMap, SourceName};
+use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName};
 use qsc_passes::PackageType;
 use qsc_project::{FileSystem, Manifest, StdFs};
 use std::{
@@ -94,7 +91,7 @@ fn main() -> miette::Result<ExitCode> {
             !cli.nostdlib,
             SourceMap::new(sources, cli.entry.map(std::convert::Into::into)),
             PackageType::Exe,
-            TargetProfile::Full,
+            RuntimeCapabilityFlags::all(),
         ) {
             Ok(interpreter) => interpreter,
             Err(errors) => {
@@ -113,7 +110,7 @@ fn main() -> miette::Result<ExitCode> {
         !cli.nostdlib,
         SourceMap::new(sources, None),
         PackageType::Lib,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     ) {
         Ok(interpreter) => interpreter,
         Err(errors) => {
diff --git a/compiler/qsc/src/compile.rs b/compiler/qsc/src/compile.rs
index 615cf99e..7640fb3c 100644
--- a/compiler/qsc/src/compile.rs
+++ b/compiler/qsc/src/compile.rs
@@ -3,7 +3,7 @@
 
 use miette::{Diagnostic, Report};
 use qsc_frontend::{
-    compile::{CompileUnit, PackageStore, SourceMap, TargetProfile},
+    compile::{CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceMap},
     error::WithSource,
 };
 use qsc_hir::hir::PackageId;
@@ -26,16 +26,16 @@ pub fn compile(
     dependencies: &[PackageId],
     sources: SourceMap,
     package_type: PackageType,
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
 ) -> (CompileUnit, Vec<Error>) {
-    let mut unit = qsc_frontend::compile::compile(store, dependencies, sources, target);
+    let mut unit = qsc_frontend::compile::compile(store, dependencies, sources, capabilities);
     let mut errors = Vec::new();
     for error in unit.errors.drain(..) {
         errors.push(WithSource::from_map(&unit.sources, error.into()));
     }
 
     if errors.is_empty() {
-        for error in run_default_passes(store.core(), &mut unit, package_type, target) {
+        for error in run_default_passes(store.core(), &mut unit, package_type, capabilities) {
             errors.push(WithSource::from_map(&unit.sources, error.into()));
         }
     }
@@ -70,9 +70,9 @@ pub fn core() -> CompileUnit {
 ///
 /// Panics if the standard library does not compile without errors.
 #[must_use]
-pub fn std(store: &PackageStore, target: TargetProfile) -> CompileUnit {
-    let mut unit = qsc_frontend::compile::std(store, target);
-    let pass_errors = run_default_passes(store.core(), &mut unit, PackageType::Lib, target);
+pub fn std(store: &PackageStore, capabilities: RuntimeCapabilityFlags) -> CompileUnit {
+    let mut unit = qsc_frontend::compile::std(store, capabilities);
+    let pass_errors = run_default_passes(store.core(), &mut unit, PackageType::Lib, capabilities);
     if pass_errors.is_empty() {
         unit
     } else {
diff --git a/compiler/qsc/src/incremental.rs b/compiler/qsc/src/incremental.rs
index 7482b616..2af37040 100644
--- a/compiler/qsc/src/incremental.rs
+++ b/compiler/qsc/src/incremental.rs
@@ -4,7 +4,7 @@
 use crate::compile::{self, compile, core, std};
 use miette::Diagnostic;
 use qsc_frontend::{
-    compile::{OpenPackageStore, PackageStore, SourceMap, TargetProfile},
+    compile::{OpenPackageStore, PackageStore, RuntimeCapabilityFlags, SourceMap},
     error::WithSource,
     incremental::Increment,
 };
@@ -36,18 +36,18 @@ impl Compiler {
         include_std: bool,
         sources: SourceMap,
         package_type: PackageType,
-        target: TargetProfile,
+        capabilities: RuntimeCapabilityFlags,
     ) -> Result<Self, Errors> {
         let core = core();
         let mut store = PackageStore::new(core);
         let mut dependencies = Vec::new();
         if include_std {
-            let std = std(&store, target);
+            let std = std(&store, capabilities);
             let id = store.insert(std);
             dependencies.push(id);
         }
 
-        let (unit, errors) = compile(&store, &dependencies, sources, package_type, target);
+        let (unit, errors) = compile(&store, &dependencies, sources, package_type, capabilities);
         if !errors.is_empty() {
             return Err(errors);
         }
@@ -55,14 +55,14 @@ impl Compiler {
         let source_package_id = store.insert(unit);
         dependencies.push(source_package_id);
 
-        let frontend = qsc_frontend::incremental::Compiler::new(&store, dependencies, target);
+        let frontend = qsc_frontend::incremental::Compiler::new(&store, dependencies, capabilities);
         let store = store.open();
 
         Ok(Self {
             store,
             source_package_id,
             frontend,
-            passes: PassContext::new(target),
+            passes: PassContext::new(capabilities),
         })
     }
 
diff --git a/compiler/qsc/src/interpret/stateful.rs b/compiler/qsc/src/interpret/stateful.rs
index 0b221dc9..2e940ac5 100644
--- a/compiler/qsc/src/interpret/stateful.rs
+++ b/compiler/qsc/src/interpret/stateful.rs
@@ -32,7 +32,7 @@ use qsc_fir::{
     visit::{self, Visitor},
 };
 use qsc_frontend::{
-    compile::{CompileUnit, PackageStore, Source, SourceMap, TargetProfile},
+    compile::{CompileUnit, PackageStore, RuntimeCapabilityFlags, Source, SourceMap},
     error::WithSource,
 };
 use qsc_passes::PackageType;
@@ -114,8 +114,8 @@ impl<'a> NodeLookup for Lookup<'a> {
 pub struct Interpreter {
     /// The incremental Q# compiler.
     compiler: Compiler,
-    /// The `TargetProfile` used for compilation.
-    target: TargetProfile,
+    /// The runtime capabilities used for compilation.
+    capabilities: RuntimeCapabilityFlags,
     /// The number of lines that have so far been compiled.
     /// This field is used to generate a unique label
     /// for each line evaluated with `eval_fragments`.
@@ -149,12 +149,13 @@ impl Interpreter {
         std: bool,
         sources: SourceMap,
         package_type: PackageType,
-        target: TargetProfile,
+        capabilities: RuntimeCapabilityFlags,
     ) -> Result<Self, Vec<Error>> {
         let mut lowerer = qsc_eval::lower::Lowerer::new();
         let mut fir_store = IndexMap::new();
 
-        let compiler = Compiler::new(std, sources, package_type, target).map_err(into_errors)?;
+        let compiler =
+            Compiler::new(std, sources, package_type, capabilities).map_err(into_errors)?;
 
         for (id, unit) in compiler.package_store().iter() {
             fir_store.insert(
@@ -169,7 +170,7 @@ impl Interpreter {
         Ok(Self {
             compiler,
             lines: 0,
-            target,
+            capabilities,
             fir_store,
             lowerer,
             env: Env::with_empty_scope(),
@@ -366,7 +367,7 @@ impl Interpreter {
     /// Performs QIR codegen using the given entry expression on a new instance of the environment
     /// and simulator but using the current compilation.
     pub fn qirgen(&mut self, expr: &str) -> Result<String, Vec<Error>> {
-        if self.target != TargetProfile::Base {
+        if self.capabilities != RuntimeCapabilityFlags::empty() {
             return Err(vec![Error::TargetMismatch]);
         }
 
diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs
index 947faf18..40204e1a 100644
--- a/compiler/qsc/src/lib.rs
+++ b/compiler/qsc/src/lib.rs
@@ -8,9 +8,10 @@ pub mod compile;
 pub mod error;
 pub mod incremental;
 pub mod interpret;
+pub mod target;
 
 pub use qsc_frontend::compile::{
-    CompileUnit, PackageStore, SourceContents, SourceMap, SourceName, TargetProfile,
+    CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName,
 };
 
 pub mod resolve {
diff --git a/compiler/qsc/src/target.rs b/compiler/qsc/src/target.rs
new file mode 100644
index 00000000..e08a7073
--- /dev/null
+++ b/compiler/qsc/src/target.rs
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use std::str::FromStr;
+
+use qsc_frontend::compile::RuntimeCapabilityFlags;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Profile {
+    Unrestricted,
+    Base,
+}
+
+impl Profile {
+    #[must_use]
+    pub fn to_str(&self) -> &'static str {
+        match self {
+            Self::Unrestricted => "Unrestricted",
+            Self::Base => "Base",
+        }
+    }
+}
+
+impl From<Profile> for RuntimeCapabilityFlags {
+    fn from(value: Profile) -> Self {
+        match value {
+            Profile::Unrestricted => Self::all(),
+            Profile::Base => Self::empty(),
+        }
+    }
+}
+
+impl FromStr for Profile {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "Unrestricted" | "unrestricted" => Ok(Self::Unrestricted),
+            "Base" | "base" => Ok(Self::Base),
+            _ => Err(()),
+        }
+    }
+}
diff --git a/compiler/qsc_frontend/Cargo.toml b/compiler/qsc_frontend/Cargo.toml
index 5b62081a..61b09045 100644
--- a/compiler/qsc_frontend/Cargo.toml
+++ b/compiler/qsc_frontend/Cargo.toml
@@ -9,6 +9,7 @@ edition.workspace = true
 license.workspace = true
 
 [dependencies]
+bitflags = { workspace = true }
 enum-iterator = { workspace = true }
 miette = { workspace = true }
 num-bigint = { workspace = true }
diff --git a/compiler/qsc_frontend/src/compile.rs b/compiler/qsc_frontend/src/compile.rs
index 91525acd..da749647 100644
--- a/compiler/qsc_frontend/src/compile.rs
+++ b/compiler/qsc_frontend/src/compile.rs
@@ -12,6 +12,7 @@ use crate::{
     resolve::{self, Names, Resolver},
     typeck::{self, Checker, Table},
 };
+use bitflags::bitflags;
 use miette::{Diagnostic, Report};
 use preprocess::TrackedName;
 use qsc_ast::{
@@ -35,13 +36,24 @@ use qsc_hir::{
 use std::{fmt::Debug, str::FromStr, sync::Arc};
 use thiserror::Error;
 
+bitflags! {
+    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+    pub struct RuntimeCapabilityFlags: u32 {
+        const ConditionalForwardBranching = 0b0000_0001;
+        const IntegerComputations = 0b0000_0010;
+        const FloatingPointComputation = 0b0000_0100;
+        const BackwardsBranching = 0b0000_1000;
+        const HigherLevelConstructs = 0b0001_0000;
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq)]
-pub enum TargetProfile {
+pub enum ConfigAttr {
     Full,
     Base,
 }
 
-impl TargetProfile {
+impl ConfigAttr {
     #[must_use]
     pub fn to_str(&self) -> &'static str {
         match self {
@@ -56,18 +68,27 @@ impl TargetProfile {
     }
 }
 
-impl FromStr for TargetProfile {
+impl FromStr for ConfigAttr {
     type Err = ();
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "Full" => Ok(TargetProfile::Full),
-            "Base" => Ok(Self::Base),
+            "Full" => Ok(ConfigAttr::Full),
+            "Base" => Ok(ConfigAttr::Base),
             _ => Err(()),
         }
     }
 }
 
+impl From<ConfigAttr> for RuntimeCapabilityFlags {
+    fn from(value: ConfigAttr) -> Self {
+        match value {
+            ConfigAttr::Full => Self::all(),
+            ConfigAttr::Base => Self::empty(),
+        }
+    }
+}
+
 #[allow(clippy::module_name_repetitions)]
 #[derive(Debug, Default)]
 pub struct CompileUnit {
@@ -302,11 +323,11 @@ pub fn compile(
     store: &PackageStore,
     dependencies: &[PackageId],
     sources: SourceMap,
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
 ) -> CompileUnit {
     let (mut ast_package, parse_errors) = parse_all(&sources);
 
-    let mut cond_compile = preprocess::Conditional::new(target);
+    let mut cond_compile = preprocess::Conditional::new(capabilities);
     cond_compile.visit_package(&mut ast_package);
     let dropped_names = cond_compile.into_names();
 
@@ -379,7 +400,7 @@ pub fn core() -> CompileUnit {
         None,
     );
 
-    let mut unit = compile(&store, &[], sources, TargetProfile::Base);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::empty());
     assert_no_errors(&unit.sources, &mut unit.errors);
     unit
 }
@@ -390,7 +411,7 @@ pub fn core() -> CompileUnit {
 ///
 /// Panics if the standard library does not compile without errors.
 #[must_use]
-pub fn std(store: &PackageStore, target: TargetProfile) -> CompileUnit {
+pub fn std(store: &PackageStore, capabilities: RuntimeCapabilityFlags) -> CompileUnit {
     let sources = SourceMap::new(
         [
             (
@@ -461,7 +482,7 @@ pub fn std(store: &PackageStore, target: TargetProfile) -> CompileUnit {
         None,
     );
 
-    let mut unit = compile(store, &[PackageId::CORE], sources, target);
+    let mut unit = compile(store, &[PackageId::CORE], sources, capabilities);
     assert_no_errors(&unit.sources, &mut unit.errors);
     unit
 }
diff --git a/compiler/qsc_frontend/src/compile/preprocess.rs b/compiler/qsc_frontend/src/compile/preprocess.rs
index cfbf5bd6..2871dab7 100644
--- a/compiler/qsc_frontend/src/compile/preprocess.rs
+++ b/compiler/qsc_frontend/src/compile/preprocess.rs
@@ -9,7 +9,7 @@ use qsc_ast::{
 use qsc_hir::hir;
 use std::rc::Rc;
 
-use super::TargetProfile;
+use super::{ConfigAttr, RuntimeCapabilityFlags};
 
 #[derive(PartialEq, Hash, Clone, Debug)]
 pub struct TrackedName {
@@ -18,15 +18,15 @@ pub struct TrackedName {
 }
 
 pub(crate) struct Conditional {
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
     dropped_names: Vec<TrackedName>,
     included_names: Vec<TrackedName>,
 }
 
 impl Conditional {
-    pub(crate) fn new(target: TargetProfile) -> Self {
+    pub(crate) fn new(capabilities: RuntimeCapabilityFlags) -> Self {
         Self {
-            target,
+            capabilities,
             dropped_names: Vec::new(),
             included_names: Vec::new(),
         }
@@ -46,7 +46,7 @@ impl MutVisitor for Conditional {
             .items
             .iter()
             .filter_map(|item| {
-                if matches_target(&item.attrs, self.target) {
+                if matches_config(&item.attrs, self.capabilities) {
                     match item.kind.as_ref() {
                         ItemKind::Callable(callable) => {
                             self.included_names.push(TrackedName {
@@ -84,7 +84,7 @@ impl MutVisitor for Conditional {
 
     fn visit_stmt(&mut self, stmt: &mut Stmt) {
         if let StmtKind::Item(item) = stmt.kind.as_mut() {
-            if matches_target(&item.attrs, self.target) {
+            if matches_config(&item.attrs, self.capabilities) {
                 match item.kind.as_ref() {
                     ItemKind::Callable(callable) => {
                         self.included_names.push(TrackedName {
@@ -118,23 +118,27 @@ impl MutVisitor for Conditional {
     }
 }
 
-fn matches_target(attrs: &[Box<Attr>], target: TargetProfile) -> bool {
+fn matches_config(attrs: &[Box<Attr>], capabilities: RuntimeCapabilityFlags) -> bool {
     attrs.iter().all(|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() {
-                    ExprKind::Path(path) => {
-                        match TargetProfile::from_str(path.name.name.as_ref()) {
-                            Ok(t) => t == target,
-                            Err(()) => true,
-                        }
-                    }
-                    _ => true,
+                    // If there is no config attribute, then we assume that the item matches
+                    // the target. We can't do membership tests on the capabilities because
+                    // Base is not a subset of any capabilities, it is a lack of capabilities.
+                    ExprKind::Path(path) => match ConfigAttr::from_str(path.name.name.as_ref()) {
+                        Ok(ConfigAttr::Full) => capabilities.is_all(),
+                        Ok(ConfigAttr::Base) => capabilities.is_empty(),
+                        _ => true,
+                    },
+                    _ => true, // Unknown config attribute, so we assume it matches
                 }
             } else {
+                // Something other than a parenthesized expression, so we assume it matches
                 true
             }
         } else {
+            // Unknown attribute, so we assume it matches
             true
         }
     })
diff --git a/compiler/qsc_frontend/src/incremental.rs b/compiler/qsc_frontend/src/incremental.rs
index 23f3d9cd..6da8546c 100644
--- a/compiler/qsc_frontend/src/incremental.rs
+++ b/compiler/qsc_frontend/src/incremental.rs
@@ -6,8 +6,8 @@ mod tests;
 
 use crate::{
     compile::{
-        self, preprocess, AstPackage, CompileUnit, Offsetter, PackageStore, SourceMap,
-        TargetProfile,
+        self, preprocess, AstPackage, CompileUnit, Offsetter, PackageStore, RuntimeCapabilityFlags,
+        SourceMap,
     },
     error::WithSource,
     lower::Lowerer,
@@ -37,7 +37,7 @@ pub struct Compiler {
     resolver: Resolver,
     checker: Checker,
     lowerer: Lowerer,
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
 }
 
 pub type Error = WithSource<compile::Error>;
@@ -56,7 +56,7 @@ impl Compiler {
     pub fn new(
         store: &PackageStore,
         dependencies: impl IntoIterator<Item = PackageId>,
-        target: TargetProfile,
+        capabilities: RuntimeCapabilityFlags,
     ) -> Self {
         let mut resolve_globals = resolve::GlobalTable::new();
         let mut typeck_globals = typeck::GlobalTable::new();
@@ -81,7 +81,7 @@ impl Compiler {
             resolver: Resolver::with_persistent_local_scope(resolve_globals, dropped_names),
             checker: Checker::new(typeck_globals),
             lowerer: Lowerer::new(),
-            target,
+            capabilities,
         }
     }
 
@@ -188,7 +188,7 @@ impl Compiler {
         unit: &mut CompileUnit,
         ast: &mut ast::Package,
     ) -> (hir::Package, Vec<Error>) {
-        let mut cond_compile = preprocess::Conditional::new(self.target);
+        let mut cond_compile = preprocess::Conditional::new(self.capabilities);
         cond_compile.visit_package(ast);
 
         self.ast_assigner.visit_package(ast);
diff --git a/compiler/qsc_frontend/src/lower.rs b/compiler/qsc_frontend/src/lower.rs
index b97e66a0..d7b5f4b1 100644
--- a/compiler/qsc_frontend/src/lower.rs
+++ b/compiler/qsc_frontend/src/lower.rs
@@ -6,7 +6,7 @@ mod tests;
 
 use crate::{
     closure::{self, Lambda, PartialApp},
-    compile::TargetProfile,
+    compile::ConfigAttr,
     resolve::{self, Names},
     typeck::{self, convert},
 };
@@ -229,7 +229,7 @@ impl With<'_> {
             Ok(hir::Attr::Config) => {
                 if !matches!(attr.arg.kind.as_ref(), ast::ExprKind::Paren(inner)
                     if matches!(inner.kind.as_ref(), ast::ExprKind::Path(path)
-                        if TargetProfile::from_str(path.name.name.as_ref()).is_ok()))
+                        if ConfigAttr::from_str(path.name.name.as_ref()).is_ok()))
                 {
                     self.lowerer
                         .errors
diff --git a/compiler/qsc_passes/src/lib.rs b/compiler/qsc_passes/src/lib.rs
index d79b8bd3..20fed5fd 100644
--- a/compiler/qsc_passes/src/lib.rs
+++ b/compiler/qsc_passes/src/lib.rs
@@ -21,7 +21,7 @@ use callable_limits::CallableLimits;
 use entry_point::generate_entry_expr;
 use loop_unification::LoopUni;
 use miette::Diagnostic;
-use qsc_frontend::compile::{CompileUnit, TargetProfile};
+use qsc_frontend::compile::{CompileUnit, RuntimeCapabilityFlags};
 use qsc_hir::{
     assigner::Assigner,
     global::{self, Table},
@@ -52,15 +52,15 @@ pub enum PackageType {
 }
 
 pub struct PassContext {
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
     borrow_check: borrowck::Checker,
 }
 
 impl PassContext {
     #[must_use]
-    pub fn new(target: TargetProfile) -> Self {
+    pub fn new(capabilities: RuntimeCapabilityFlags) -> Self {
         Self {
-            target,
+            capabilities,
             borrow_check: borrowck::Checker::default(),
         }
     }
@@ -100,7 +100,7 @@ impl PassContext {
         ReplaceQubitAllocation::new(core, assigner).visit_package(package);
         Validator::default().visit_package(package);
 
-        let base_prof_errors = if self.target == TargetProfile::Base {
+        let base_prof_errors = if self.capabilities == RuntimeCapabilityFlags::empty() {
             baseprofck::check_base_profile_compliance(package)
         } else {
             Vec::new()
@@ -123,9 +123,9 @@ pub fn run_default_passes(
     core: &Table,
     unit: &mut CompileUnit,
     package_type: PackageType,
-    target: TargetProfile,
+    capabilities: RuntimeCapabilityFlags,
 ) -> Vec<Error> {
-    PassContext::new(target).run_default_passes(
+    PassContext::new(capabilities).run_default_passes(
         &mut unit.package,
         &mut unit.assigner,
         core,
diff --git a/fuzz/fuzz_targets/compile.rs b/fuzz/fuzz_targets/compile.rs
index 798d53e7..cf92043f 100644
--- a/fuzz/fuzz_targets/compile.rs
+++ b/fuzz/fuzz_targets/compile.rs
@@ -5,14 +5,14 @@
 
 #[cfg(feature = "do_fuzz")]
 use libfuzzer_sys::fuzz_target;
-use qsc::{hir::PackageId, PackageStore, SourceMap, TargetProfile};
+use qsc::{hir::PackageId, target::Profile, PackageStore, SourceMap};
 
 fn compile(data: &[u8]) {
     if let Ok(fuzzed_code) = std::str::from_utf8(data) {
         thread_local! {
             static STORE_STD: (PackageStore, PackageId) = {
                 let mut store = PackageStore::new(qsc::compile::core());
-                let std = store.insert(qsc::compile::std(&store, TargetProfile::Full));
+                let std = store.insert(qsc::compile::std(&store, Profile::Unrestricted.into()));
                 (store, std)
             };
         }
@@ -23,7 +23,7 @@ fn compile(data: &[u8]) {
                 &[*std],
                 sources,
                 qsc::PackageType::Lib,
-                TargetProfile::Full,
+                Profile::Unrestricted.into(),
             );
         });
     }
diff --git a/katas/src/lib.rs b/katas/src/lib.rs
index 6c16fd69..b095c1bc 100644
--- a/katas/src/lib.rs
+++ b/katas/src/lib.rs
@@ -13,7 +13,8 @@ use qsc::{
         stateful::{self, Interpreter},
         Value,
     },
-    PackageType, SourceContents, SourceMap, SourceName, TargetProfile,
+    target::Profile,
+    PackageType, SourceContents, SourceMap, SourceName,
 };
 
 pub const EXAMPLE_ENTRY: &str = "Kata.RunExample()";
@@ -32,8 +33,12 @@ pub fn check_solution(
     receiver: &mut impl Receiver,
 ) -> Result<bool, Vec<stateful::Error>> {
     let source_map = SourceMap::new(exercise_sources, Some(EXERCISE_ENTRY.into()));
-    let mut interpreter: Interpreter =
-        Interpreter::new(true, source_map, PackageType::Exe, TargetProfile::Full)?;
+    let mut interpreter: Interpreter = Interpreter::new(
+        true,
+        source_map,
+        PackageType::Exe,
+        Profile::Unrestricted.into(),
+    )?;
     interpreter.eval_entry(receiver).map(|value| {
         if let Value::Bool(success) = value {
             success
diff --git a/language_service/src/compilation.rs b/language_service/src/compilation.rs
index 2d2d5610..656cfd6c 100644
--- a/language_service/src/compilation.rs
+++ b/language_service/src/compilation.rs
@@ -7,7 +7,9 @@ use qsc::{
     compile::{self, Error},
     hir::{self, PackageId},
     incremental::Compiler,
-    resolve, CompileUnit, PackageStore, PackageType, SourceMap, TargetProfile,
+    resolve,
+    target::Profile,
+    CompileUnit, PackageStore, PackageType, SourceMap,
 };
 use std::{iter::successors, sync::Arc};
 
@@ -39,7 +41,7 @@ impl Compilation {
     pub(crate) fn new(
         sources: &[(Arc<str>, Arc<str>)],
         package_type: PackageType,
-        target_profile: TargetProfile,
+        target_profile: Profile,
     ) -> Self {
         if sources.len() == 1 {
             trace!("compiling single-file document {}", sources[0].0);
@@ -50,14 +52,15 @@ impl Compilation {
         let source_map = SourceMap::new(sources.iter().map(|(x, y)| (x.clone(), y.clone())), None);
 
         let mut package_store = PackageStore::new(compile::core());
-        let std_package_id = package_store.insert(compile::std(&package_store, target_profile));
+        let std_package_id =
+            package_store.insert(compile::std(&package_store, target_profile.into()));
 
         let (unit, errors) = compile::compile(
             &package_store,
             &[std_package_id],
             source_map,
             package_type,
-            target_profile,
+            target_profile.into(),
         );
 
         let package_id = package_store.insert(unit);
@@ -71,14 +74,18 @@ impl Compilation {
     }
 
     /// Creates a new `Compilation` by compiling sources from notebook cells.
-    pub(crate) fn new_notebook<I>(cells: I, target_profile: TargetProfile) -> Self
+    pub(crate) fn new_notebook<I>(cells: I, target_profile: Profile) -> Self
     where
         I: Iterator<Item = (Arc<str>, Arc<str>)>,
     {
         trace!("compiling notebook");
-        let mut compiler =
-            Compiler::new(true, SourceMap::default(), PackageType::Lib, target_profile)
-                .expect("expected incremental compiler creation to succeed");
+        let mut compiler = Compiler::new(
+            true,
+            SourceMap::default(),
+            PackageType::Lib,
+            target_profile.into(),
+        )
+        .expect("expected incremental compiler creation to succeed");
 
         let mut errors = Vec::new();
         for (name, contents) in cells {
@@ -123,7 +130,7 @@ impl Compilation {
     }
 
     /// Regenerates the compilation with the same sources but the passed in workspace configuration options.
-    pub fn recompile(&mut self, package_type: PackageType, target_profile: TargetProfile) {
+    pub fn recompile(&mut self, package_type: PackageType, target_profile: Profile) {
         let sources: Vec<_> = self
             .user_source_contents()
             .into_iter()
diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs
index 6c062963..bd278b2a 100644
--- a/language_service/src/lib.rs
+++ b/language_service/src/lib.rs
@@ -30,7 +30,7 @@ use protocol::{
     CompletionList, DiagnosticUpdate, Hover, Location, NotebookMetadata, SignatureHelp,
     WorkspaceConfigurationUpdate,
 };
-use qsc::{compile::Error, PackageType, TargetProfile};
+use qsc::{compile::Error, target::Profile, PackageType};
 use qsc_project::FileSystemAsync;
 use rustc_hash::{FxHashMap, FxHashSet};
 use std::{future::Future, mem::take, pin::Pin, sync::Arc};
@@ -106,14 +106,14 @@ pub enum PendingUpdate {
 
 #[derive(Debug)]
 struct Configuration {
-    pub target_profile: TargetProfile,
+    pub target_profile: Profile,
     pub package_type: PackageType,
 }
 
 impl Default for Configuration {
     fn default() -> Self {
         Self {
-            target_profile: TargetProfile::Full,
+            target_profile: Profile::Unrestricted,
             package_type: PackageType::Exe,
         }
     }
@@ -121,7 +121,7 @@ impl Default for Configuration {
 
 #[derive(Default)]
 struct PartialConfiguration {
-    pub target_profile: Option<TargetProfile>,
+    pub target_profile: Option<Profile>,
     pub package_type: Option<PackageType>,
 }
 
diff --git a/language_service/src/protocol.rs b/language_service/src/protocol.rs
index c2e5ce47..c4c818e8 100644
--- a/language_service/src/protocol.rs
+++ b/language_service/src/protocol.rs
@@ -1,12 +1,12 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use qsc::{compile::Error, PackageType, TargetProfile};
+use qsc::{compile::Error, target::Profile, PackageType};
 
 /// Workspace configuration
 #[derive(Clone, Debug, Default)]
 pub struct WorkspaceConfigurationUpdate {
-    pub target_profile: Option<TargetProfile>,
+    pub target_profile: Option<Profile>,
     pub package_type: Option<PackageType>,
 }
 
@@ -100,5 +100,5 @@ pub struct ParameterInformation {
 
 #[derive(Default)]
 pub struct NotebookMetadata {
-    pub target_profile: Option<TargetProfile>,
+    pub target_profile: Option<Profile>,
 }
diff --git a/npm/src/browser.ts b/npm/src/browser.ts
index 08bb2742..6181c0da 100644
--- a/npm/src/browser.ts
+++ b/npm/src/browser.ts
@@ -5,6 +5,7 @@
 // the "./main.js" module is the entry point.
 
 import initWasm, * as wasm from "../lib/web/qsc_wasm.js";
+import { TargetProfile } from "../lib/web/qsc_wasm.js";
 import { Compiler, ICompiler, ICompilerWorker } from "./compiler/compiler.js";
 import { createCompilerProxy } from "./compiler/worker-proxy.js";
 import {
@@ -226,7 +227,7 @@ export {
 } from "./katas.js";
 export { default as samples } from "./samples.generated.js";
 export { type VSDiagnostic } from "./vsdiagnostic.js";
-export { log, type LogLevel };
+export { log, type LogLevel, type TargetProfile };
 export type { ICompilerWorker, ICompiler };
 export type { ILanguageServiceWorker, ILanguageService };
 export type { IDebugServiceWorker, IDebugService };
diff --git a/npm/src/debug-service/debug-service.ts b/npm/src/debug-service/debug-service.ts
index 48f0f9ee..5af0ef3e 100644
--- a/npm/src/debug-service/debug-service.ts
+++ b/npm/src/debug-service/debug-service.ts
@@ -9,6 +9,7 @@ import type {
   IVariable,
   IQuantumState,
 } from "../../lib/node/qsc_wasm.cjs";
+import { TargetProfile } from "../browser.js";
 import { eventStringToMsg } from "../compiler/common.js";
 import { IQscEventTarget, QscEvents, makeEvent } from "../compiler/events.js";
 import { log } from "../log.js";
@@ -22,7 +23,7 @@ export interface IDebugService {
   loadSource(
     path: string,
     source: string,
-    target: "base" | "full",
+    target: TargetProfile,
     entry: string | undefined,
   ): Promise<string>;
   getBreakpoints(path: string): Promise<IBreakpointSpan[]>;
@@ -66,7 +67,7 @@ export class QSharpDebugService implements IDebugService {
   async loadSource(
     path: string,
     source: string,
-    target: "base" | "full",
+    target: TargetProfile,
     entry: string | undefined,
   ): Promise<string> {
     this.code[path] = source;
diff --git a/pip/qsharp/_qsharp.py b/pip/qsharp/_qsharp.py
index 70f59fd1..913b840c 100644
--- a/pip/qsharp/_qsharp.py
+++ b/pip/qsharp/_qsharp.py
@@ -9,7 +9,7 @@ import json
 _interpreter = None
 
 
-def init(target_profile: TargetProfile = TargetProfile.Full) -> None:
+def init(target_profile: TargetProfile = TargetProfile.Unrestricted) -> None:
     """
     Initializes the Q# interpreter.
 
@@ -172,8 +172,8 @@ class Config:
 
     def __init__(self, target_profile: TargetProfile):
         match target_profile:
-            case TargetProfile.Full:
-                target_profile = "full"
+            case TargetProfile.Unrestricted:
+                target_profile = "unrestricted"
             case TargetProfile.Base:
                 target_profile = "base"
         self._config = {"targetProfile": target_profile}
diff --git a/pip/src/interpreter.rs b/pip/src/interpreter.rs
index 3baba73f..0d5dd490 100644
--- a/pip/src/interpreter.rs
+++ b/pip/src/interpreter.rs
@@ -23,6 +23,7 @@ use qsc::{
         },
         Value,
     },
+    target::Profile,
     PackageType, SourceMap,
 };
 use rustc_hash::FxHashMap;
@@ -52,7 +53,7 @@ pub(crate) enum TargetProfile {
     /// 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.
-    Full,
+    Unrestricted,
     /// 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.
@@ -71,10 +72,15 @@ impl Interpreter {
     /// Initializes a new Q# interpreter.
     pub(crate) fn new(_py: Python, target: TargetProfile) -> PyResult<Self> {
         let target = match target {
-            TargetProfile::Full => qsc::TargetProfile::Full,
-            TargetProfile::Base => qsc::TargetProfile::Base,
+            TargetProfile::Unrestricted => Profile::Unrestricted,
+            TargetProfile::Base => Profile::Base,
         };
-        match stateful::Interpreter::new(true, SourceMap::default(), PackageType::Lib, target) {
+        match stateful::Interpreter::new(
+            true,
+            SourceMap::default(),
+            PackageType::Lib,
+            target.into(),
+        ) {
             Ok(interpreter) => Ok(Self { interpreter }),
             Err(errors) => {
                 let mut message = String::new();
diff --git a/vscode/package.json b/vscode/package.json
index 84a08f22..982b63a7 100644
--- a/vscode/package.json
+++ b/vscode/package.json
@@ -98,13 +98,13 @@
       "properties": {
         "Q#.targetProfile": {
           "type": "string",
-          "default": "full",
+          "default": "unrestricted",
           "enum": [
-            "full",
+            "unrestricted",
             "base"
           ],
           "enumDescriptions": [
-            "The full set of capabilities required to run any Q# program. This option maps to the Full Profile as defined by the QIR specification.",
+            "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."
           ],
           "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."
diff --git a/vscode/src/config.ts b/vscode/src/config.ts
index 54adb257..75e031ac 100644
--- a/vscode/src/config.ts
+++ b/vscode/src/config.ts
@@ -1,25 +1,24 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { log } from "qsharp-lang";
+import { TargetProfile, log } from "qsharp-lang";
 import * as vscode from "vscode";
-export type Target = "base" | "full";
 
-export function getTarget(): Target {
+export function getTarget(): TargetProfile {
   const target = vscode.workspace
     .getConfiguration("Q#")
-    .get<string>("targetProfile", "full");
+    .get<TargetProfile>("targetProfile", "unrestricted");
   switch (target) {
     case "base":
-    case "full":
+    case "unrestricted":
       return target;
     default:
       log.error("invalid target found: %s", target);
-      return "full";
+      return "unrestricted";
   }
 }
 
-export async function setTarget(target: Target) {
+export async function setTarget(target: TargetProfile) {
   const config = vscode.workspace.getConfiguration("Q#");
   await config.update(
     "targetProfile",
diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts
index c9383f9a..96abaa28 100644
--- a/vscode/src/extension.ts
+++ b/vscode/src/extension.ts
@@ -238,7 +238,7 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) {
 
   switch (targetProfile) {
     case "base":
-    case "full":
+    case "unrestricted":
       break;
     default:
       log.warn(`Invalid value for target profile: ${targetProfile}`);
@@ -246,7 +246,7 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) {
   log.debug("Target profile set to: " + targetProfile);
 
   languageService.updateConfiguration({
-    targetProfile: targetProfile as "base" | "full",
+    targetProfile: targetProfile,
   });
 }
 
diff --git a/vscode/src/statusbar.ts b/vscode/src/statusbar.ts
index e7855f7f..dbbd5970 100644
--- a/vscode/src/statusbar.ts
+++ b/vscode/src/statusbar.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { log } from "qsharp-lang";
+import { log, TargetProfile } from "qsharp-lang";
 import * as vscode from "vscode";
 import { isQsharpDocument } from "./common";
 import { getTarget, setTarget } from "./config";
@@ -90,29 +90,29 @@ function registerTargetProfileCommand() {
 
 const targetProfiles = [
   { configName: "base", uiText: "QIR:Base" },
-  { configName: "full", uiText: "QIR:Full" },
+  { configName: "unrestricted", uiText: "Unrestricted" },
 ];
 
 function getTargetProfileUiText(targetProfile?: string) {
   switch (targetProfile) {
     case "base":
       return "QIR:Base";
-    case "full":
-      return "QIR:Full";
+    case "unrestricted":
+      return "Unrestricted";
     default:
       log.error("invalid target profile found");
       return "QIR:Invalid";
   }
 }
 
-function getTargetProfileSetting(uiText: string) {
+function getTargetProfileSetting(uiText: string): TargetProfile {
   switch (uiText) {
     case "QIR:Base":
       return "base";
-    case "QIR:Full":
-      return "full";
+    case "Unrestricted":
+      return "unrestricted";
     default:
       log.error("invalid target profile found");
-      return "full";
+      return "unrestricted";
   }
 }
diff --git a/wasm/src/debug_service.rs b/wasm/src/debug_service.rs
index fffb5dca..7edd16fc 100644
--- a/wasm/src/debug_service.rs
+++ b/wasm/src/debug_service.rs
@@ -1,10 +1,12 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+use std::str::FromStr;
+
 use qsc::fir::StmtId;
 use qsc::interpret::stateful::Interpreter;
 use qsc::interpret::{stateful, StepAction, StepResult};
-use qsc::{fmt_complex, PackageType, SourceMap, TargetProfile};
+use qsc::{fmt_complex, target::Profile, PackageType, SourceMap};
 
 use crate::{serializable_type, CallbackReceiver};
 use serde::{Deserialize, Serialize};
@@ -25,7 +27,7 @@ impl DebugService {
                 false,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Full,
+                Profile::Unrestricted.into(),
             )
             .expect("Couldn't create interpreter"),
         }
@@ -42,12 +44,9 @@ impl DebugService {
             [(path.into(), source.into())],
             entry.as_deref().map(|value| value.into()),
         );
-        let target = match target_profile.as_str() {
-            "base" => TargetProfile::Base,
-            "full" => TargetProfile::Full,
-            _ => panic!("Invalid target : {}", target_profile),
-        };
-        match Interpreter::new(true, source_map, qsc::PackageType::Exe, target) {
+        let target = Profile::from_str(&target_profile)
+            .unwrap_or_else(|_| panic!("Invalid target : {}", target_profile));
+        match Interpreter::new(true, source_map, PackageType::Exe, target.into()) {
             Ok(interpreter) => {
                 self.interpreter = interpreter;
                 match self.interpreter.set_entry() {
diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs
index 97ad5712..d1e73d9a 100644
--- a/wasm/src/language_service.rs
+++ b/wasm/src/language_service.rs
@@ -1,11 +1,11 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use std::{future::Future, path::PathBuf, pin::Pin, sync::Arc};
+use std::{future::Future, path::PathBuf, pin::Pin, str::FromStr, sync::Arc};
 
 use crate::{diagnostic::VSDiagnostic, serializable_type};
 use js_sys::JsString;
-use qsc::{self};
+use qsc::{self, target::Profile, PackageType};
 use qsc_project::{EntryType, Manifest, ManifestDescriptor};
 use qsls::{protocol::DiagnosticUpdate, JSFileEntry};
 use rustc_hash::FxHashMap;
@@ -199,10 +199,12 @@ impl LanguageService {
         let config: WorkspaceConfiguration = config.into();
         self.0
             .update_configuration(&qsls::protocol::WorkspaceConfigurationUpdate {
-                target_profile: config.targetProfile.map(into_target_profile),
+                target_profile: config
+                    .targetProfile
+                    .map(|s| Profile::from_str(&s).expect("invalid target profile")),
                 package_type: config.packageType.map(|s| match s.as_str() {
-                    "lib" => qsc::PackageType::Lib,
-                    "exe" => qsc::PackageType::Exe,
+                    "lib" => PackageType::Lib,
+                    "exe" => PackageType::Exe,
                     _ => panic!("invalid package type"),
                 }),
             })
@@ -227,7 +229,9 @@ impl LanguageService {
         self.0.update_notebook_document(
             notebook_uri,
             &qsls::protocol::NotebookMetadata {
-                target_profile: notebook_metadata.targetProfile.map(into_target_profile),
+                target_profile: notebook_metadata
+                    .targetProfile
+                    .map(|s| Profile::from_str(&s).expect("invalid target profile")),
             },
             cells
                 .iter()
@@ -403,7 +407,7 @@ serializable_type! {
         pub packageType: Option<String>,
     },
     r#"export interface IWorkspaceConfiguration {
-        targetProfile?: "full" | "base";
+        targetProfile?: TargetProfile;
         packageType?: "exe" | "lib";
     }"#,
     IWorkspaceConfiguration
@@ -562,7 +566,7 @@ serializable_type! {
         pub targetProfile: Option<String>,
     },
     r#"export interface INotebookMetadata {
-        targetProfile?: "full" | "base";
+        targetProfile?: "unrestricted" | "base";
     }"#,
     INotebookMetadata
 }
@@ -594,11 +598,3 @@ extern "C" {
     )]
     pub type GetManifestCallback;
 }
-
-fn into_target_profile(value: String) -> qsc::TargetProfile {
-    match value.as_str() {
-        "base" => qsc::TargetProfile::Base,
-        "full" => qsc::TargetProfile::Full,
-        _ => panic!("invalid target profile"),
-    }
-}
diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs
index 261f51ea..49704af8 100644
--- a/wasm/src/lib.rs
+++ b/wasm/src/lib.rs
@@ -12,7 +12,8 @@ use qsc::{
         output::{self, Receiver},
         stateful::{self, re::estimate_entry},
     },
-    PackageStore, PackageType, SourceContents, SourceMap, SourceName, TargetProfile,
+    target::Profile,
+    PackageStore, PackageType, SourceContents, SourceMap, SourceName,
 };
 use qsc_codegen::qir_base::generate_qir;
 use serde_json::json;
@@ -31,7 +32,7 @@ mod tests;
 thread_local! {
     static STORE_CORE_STD: (PackageStore, PackageId) = {
         let mut store = PackageStore::new(compile::core());
-        let std = store.insert(compile::std(&store, TargetProfile::Full));
+        let std = store.insert(compile::std(&store, Profile::Unrestricted.into()));
         (store, std)
     };
 }
@@ -46,7 +47,7 @@ pub fn git_hash() -> String {
 pub fn get_qir(code: &str) -> Result<String, String> {
     let core = compile::core();
     let mut store = PackageStore::new(core);
-    let std = compile::std(&store, TargetProfile::Base);
+    let std = compile::std(&store, Profile::Base.into());
     let std = store.insert(std);
     let sources = SourceMap::new([("test".into(), code.into())], None);
 
@@ -55,7 +56,7 @@ pub fn get_qir(code: &str) -> Result<String, String> {
         &[std],
         sources,
         PackageType::Exe,
-        TargetProfile::Base,
+        Profile::Base.into(),
     );
 
     // Ensure it compiles before trying to add it to the store.
@@ -76,7 +77,7 @@ pub fn get_estimates(code: &str, params: &str) -> Result<String, String> {
         true,
         SourceMap::new([("code".into(), code.into())], None),
         PackageType::Exe,
-        TargetProfile::Full,
+        Profile::Unrestricted.into(),
     )
     .map_err(|e| e[0].to_string())?;
 
@@ -110,7 +111,7 @@ pub fn get_hir(code: &str) -> String {
             &[*std],
             sources,
             PackageType::Exe,
-            TargetProfile::Full,
+            Profile::Unrestricted.into(),
         );
         unit.package
     });
@@ -180,8 +181,12 @@ where
     let source_name = "code";
     let mut out = CallbackReceiver { event_cb };
     let sources = SourceMap::new([(source_name.into(), code.into())], Some(expr.into()));
-    let interpreter =
-        stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full);
+    let interpreter = stateful::Interpreter::new(
+        true,
+        sources,
+        PackageType::Exe,
+        Profile::Unrestricted.into(),
+    );
     if let Err(err) = interpreter {
         // TODO: handle multiple errors
         // https://github.com/microsoft/qsharp/issues/149
@@ -284,3 +289,8 @@ pub fn check_exercise_solution(
         let _ = event_cb.call1(&JsValue::null(), &JsValue::from_str(msg));
     })
 }
+
+#[wasm_bindgen(typescript_custom_section)]
+const TARGET_PROFILE: &'static str = r#"
+export type TargetProfile = "base" | "unrestricted";
+"#;


Test patch:
diff --git a/compiler/qsc/src/interpret/debug/tests.rs b/compiler/qsc/src/interpret/debug/tests.rs
index 6c91c648..ef68f0a0 100644
--- a/compiler/qsc/src/interpret/debug/tests.rs
+++ b/compiler/qsc/src/interpret/debug/tests.rs
@@ -6,7 +6,7 @@
 use indoc::indoc;
 use miette::Result;
 use qsc_eval::{output::CursorReceiver, val::Value};
-use qsc_frontend::compile::{SourceMap, TargetProfile};
+use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceMap};
 use qsc_passes::PackageType;
 use std::io::Cursor;
 
@@ -65,8 +65,13 @@ fn stack_traces_can_cross_eval_session_and_file_boundaries() {
         ],
         None,
     );
-    let mut interpreter = Interpreter::new(true, source_map, PackageType::Lib, TargetProfile::Full)
-        .expect("Failed to compile base environment.");
+    let mut interpreter = Interpreter::new(
+        true,
+        source_map,
+        PackageType::Lib,
+        RuntimeCapabilityFlags::all(),
+    )
+    .expect("Failed to compile base environment.");
 
     let (result, _) = line(
         &mut interpreter,
@@ -134,8 +139,13 @@ fn stack_traces_can_cross_file_and_entry_boundaries() {
         ],
         Some("Adjoint Test2.A(0)".into()),
     );
-    let mut interpreter = Interpreter::new(true, source_map, PackageType::Exe, TargetProfile::Full)
-        .expect("Failed to compile base environment.");
+    let mut interpreter = Interpreter::new(
+        true,
+        source_map,
+        PackageType::Exe,
+        RuntimeCapabilityFlags::all(),
+    )
+    .expect("Failed to compile base environment.");
 
     let (result, _) = eval(&mut interpreter);
 
diff --git a/compiler/qsc/src/interpret/stateful/re/counts/tests.rs b/compiler/qsc/src/interpret/stateful/re/counts/tests.rs
index 0ac7ab5e..741050e3 100644
--- a/compiler/qsc/src/interpret/stateful/re/counts/tests.rs
+++ b/compiler/qsc/src/interpret/stateful/re/counts/tests.rs
@@ -5,7 +5,8 @@ use std::convert::Into;
 
 use crate::{
     interpret::{stateful::Interpreter, GenericReceiver},
-    PackageType, SourceMap, TargetProfile,
+    target::Profile,
+    PackageType, SourceMap,
 };
 use expect_test::{expect, Expect};
 use indoc::indoc;
@@ -14,8 +15,13 @@ use super::LogicalCounter;
 
 fn veryify_logical_counts(source: &str, entry: Option<&str>, expect: &Expect) {
     let source_map = SourceMap::new([("test".into(), source.into())], entry.map(Into::into));
-    let mut interpreter = Interpreter::new(true, source_map, PackageType::Exe, TargetProfile::Full)
-        .expect("compilation should succeed");
+    let mut interpreter = Interpreter::new(
+        true,
+        source_map,
+        PackageType::Exe,
+        Profile::Unrestricted.into(),
+    )
+    .expect("compilation should succeed");
     let mut counter = LogicalCounter::default();
     let mut stdout = std::io::sink();
     let mut out = GenericReceiver::new(&mut stdout);
diff --git a/compiler/qsc/src/interpret/stateful/stepping_tests.rs b/compiler/qsc/src/interpret/stateful/stepping_tests.rs
index da9d138a..f1033db9 100644
--- a/compiler/qsc/src/interpret/stateful/stepping_tests.rs
+++ b/compiler/qsc/src/interpret/stateful/stepping_tests.rs
@@ -6,7 +6,7 @@
 use crate::interpret::stateful::Interpreter;
 use qsc_eval::{output::CursorReceiver, StepAction, StepResult};
 use qsc_fir::fir::StmtId;
-use qsc_frontend::compile::{SourceMap, TargetProfile};
+use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceMap};
 use qsc_passes::PackageType;
 use std::io::Cursor;
 
@@ -41,8 +41,12 @@ mod given_interpreter_with_sources {
         #[test]
         fn in_one_level_operation_works() -> Result<(), Vec<crate::interpret::stateful::Error>> {
             let sources = SourceMap::new([("test".into(), STEPPING_SOURCE.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)?;
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Exe,
+                RuntimeCapabilityFlags::all(),
+            )?;
             interpreter.set_entry()?;
             let ids = get_breakpoint_ids(&interpreter, "test");
             let expected_id = ids[0];
@@ -61,8 +65,12 @@ mod given_interpreter_with_sources {
         #[test]
         fn next_crosses_operation_works() -> Result<(), Vec<crate::interpret::stateful::Error>> {
             let sources = SourceMap::new([("test".into(), STEPPING_SOURCE.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)?;
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Exe,
+                RuntimeCapabilityFlags::all(),
+            )?;
             interpreter.set_entry()?;
             let ids = get_breakpoint_ids(&interpreter, "test");
             let expected_id = ids[0];
@@ -77,8 +85,12 @@ mod given_interpreter_with_sources {
         #[test]
         fn in_multiple_operations_works() -> Result<(), Vec<crate::interpret::stateful::Error>> {
             let sources = SourceMap::new([("test".into(), STEPPING_SOURCE.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)?;
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Exe,
+                RuntimeCapabilityFlags::all(),
+            )?;
             interpreter.set_entry()?;
             let ids = get_breakpoint_ids(&interpreter, "test");
             let expected_id = ids[0];
@@ -100,8 +112,12 @@ mod given_interpreter_with_sources {
         #[test]
         fn out_multiple_operations_works() -> Result<(), Vec<crate::interpret::stateful::Error>> {
             let sources = SourceMap::new([("test".into(), STEPPING_SOURCE.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)?;
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Exe,
+                RuntimeCapabilityFlags::all(),
+            )?;
             interpreter.set_entry()?;
             let ids = get_breakpoint_ids(&interpreter, "test");
             let expected_id = ids[0];
diff --git a/compiler/qsc/src/interpret/stateful/tests.rs b/compiler/qsc/src/interpret/stateful/tests.rs
index df354911..88ec75d1 100644
--- a/compiler/qsc/src/interpret/stateful/tests.rs
+++ b/compiler/qsc/src/interpret/stateful/tests.rs
@@ -8,7 +8,7 @@ mod given_interpreter {
     use expect_test::Expect;
     use miette::Diagnostic;
     use qsc_eval::{output::CursorReceiver, val::Value};
-    use qsc_frontend::compile::{SourceMap, TargetProfile};
+    use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceMap};
     use qsc_passes::PackageType;
     use std::{fmt::Write, io::Cursor, iter, str::from_utf8};
 
@@ -45,11 +45,12 @@ mod given_interpreter {
     mod without_sources {
         use expect_test::expect;
         use indoc::indoc;
+        use qsc_frontend::compile::RuntimeCapabilityFlags;
 
         use super::*;
 
         mod without_stdlib {
-            use qsc_frontend::compile::{SourceMap, TargetProfile};
+            use qsc_frontend::compile::SourceMap;
             use qsc_passes::PackageType;
 
             use super::*;
@@ -60,7 +61,7 @@ mod given_interpreter {
                     false,
                     SourceMap::default(),
                     PackageType::Lib,
-                    TargetProfile::Full,
+                    RuntimeCapabilityFlags::all(),
                 )
                 .expect("interpreter should be created");
 
@@ -553,7 +554,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let (result, output) = line(
@@ -619,7 +620,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let (result, output) = line(
@@ -685,7 +686,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let (result, output) = line(
@@ -766,7 +767,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let (result, output) = line(
@@ -792,7 +793,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let (result, output) = line(
@@ -878,7 +879,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let res = interpreter
@@ -941,7 +942,7 @@ mod given_interpreter {
                 true,
                 SourceMap::default(),
                 PackageType::Lib,
-                TargetProfile::Base,
+                RuntimeCapabilityFlags::empty(),
             )
             .expect("interpreter should be created");
             let res = interpreter
@@ -1049,7 +1050,7 @@ mod given_interpreter {
         use super::*;
         use expect_test::expect;
         use indoc::indoc;
-        use qsc_frontend::compile::{SourceMap, TargetProfile};
+        use qsc_frontend::compile::{RuntimeCapabilityFlags, SourceMap};
         use qsc_passes::PackageType;
 
         #[test]
@@ -1063,9 +1064,13 @@ mod given_interpreter {
             }"#};
 
             let sources = SourceMap::new([("test".into(), source.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-                    .expect("interpreter should be created");
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Exe,
+                RuntimeCapabilityFlags::all(),
+            )
+            .expect("interpreter should be created");
 
             let (result, output) = entry(&mut interpreter);
             is_unit_with_output_eval_entry(&result, &output, "hello there...");
@@ -1081,9 +1086,13 @@ mod given_interpreter {
             }"#};
 
             let sources = SourceMap::new([("test".into(), source.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Lib, TargetProfile::Full)
-                    .expect("interpreter should be created");
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Lib,
+                RuntimeCapabilityFlags::all(),
+            )
+            .expect("interpreter should be created");
 
             let (result, output) = line(&mut interpreter, "Test.Main()");
             is_unit_with_output(&result, &output, "hello there...");
@@ -1103,9 +1112,13 @@ mod given_interpreter {
             }"#};
 
             let sources = SourceMap::new([("test".into(), source.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Lib, TargetProfile::Full)
-                    .expect("interpreter should be created");
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Lib,
+                RuntimeCapabilityFlags::all(),
+            )
+            .expect("interpreter should be created");
 
             let (result, output) = line(&mut interpreter, "Test.Hello()");
             is_only_value(&result, &output, &Value::String("hello there...".into()));
@@ -1129,9 +1142,13 @@ mod given_interpreter {
             }"#};
 
             let sources = SourceMap::new([("test".into(), source.into())], None);
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Lib, TargetProfile::Full)
-                    .expect("interpreter should be created");
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Lib,
+                RuntimeCapabilityFlags::all(),
+            )
+            .expect("interpreter should be created");
             let (result, output) = line(&mut interpreter, "Test.Hello()");
             is_only_value(&result, &output, &Value::String("hello there...".into()));
             let (result, output) = line(&mut interpreter, "Test2.Main()");
@@ -1155,9 +1172,13 @@ mod given_interpreter {
                 Some("Foo.Bar()".into()),
             );
 
-            let mut interpreter =
-                Interpreter::new(true, sources, PackageType::Lib, TargetProfile::Full)
-                    .expect("interpreter should be created");
+            let mut interpreter = Interpreter::new(
+                true,
+                sources,
+                PackageType::Lib,
+                RuntimeCapabilityFlags::all(),
+            )
+            .expect("interpreter should be created");
             let (result, output) = entry(&mut interpreter);
             is_only_error(
                 &result,
@@ -1175,7 +1196,7 @@ mod given_interpreter {
             true,
             SourceMap::default(),
             PackageType::Lib,
-            TargetProfile::Full,
+            RuntimeCapabilityFlags::all(),
         )
         .expect("interpreter should be created")
     }
diff --git a/compiler/qsc_codegen/src/qir_base/tests.rs b/compiler/qsc_codegen/src/qir_base/tests.rs
index 24f92aee..9a94eeeb 100644
--- a/compiler/qsc_codegen/src/qir_base/tests.rs
+++ b/compiler/qsc_codegen/src/qir_base/tests.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_passes::{run_core_passes, run_default_passes, PackageType};
 
 use crate::qir_base::generate_qir;
@@ -17,12 +17,12 @@ fn check(program: &str, expr: Option<&str>, expect: &Expect) {
     let mut core = compile::core();
     assert!(run_core_passes(&mut core).is_empty());
     let mut store = PackageStore::new(core);
-    let mut std = compile::std(&store, TargetProfile::Base);
+    let mut std = compile::std(&store, RuntimeCapabilityFlags::empty());
     assert!(run_default_passes(
         store.core(),
         &mut std,
         PackageType::Lib,
-        TargetProfile::Base
+        RuntimeCapabilityFlags::empty()
     )
     .is_empty());
     let std = store.insert(std);
@@ -30,13 +30,13 @@ fn check(program: &str, expr: Option<&str>, expect: &Expect) {
     let expr_as_arc: Option<Arc<str>> = expr.map(|s| Arc::from(s.to_string()));
     let sources = SourceMap::new([("test".into(), program.into())], expr_as_arc);
 
-    let mut unit = compile(&store, &[std], sources, TargetProfile::Base);
+    let mut unit = compile(&store, &[std], sources, RuntimeCapabilityFlags::empty());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
     assert!(run_default_passes(
         store.core(),
         &mut unit,
         PackageType::Exe,
-        TargetProfile::Base
+        RuntimeCapabilityFlags::empty()
     )
     .is_empty());
     let package = store.insert(unit);
diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs
index 3d4b140f..7eae613e 100644
--- a/compiler/qsc_eval/src/intrinsic/tests.rs
+++ b/compiler/qsc_eval/src/intrinsic/tests.rs
@@ -19,7 +19,7 @@ use indoc::indoc;
 use num_bigint::BigInt;
 use qsc_data_structures::index_map::IndexMap;
 use qsc_fir::fir::{BlockId, ExprId, PackageId, PatId, StmtId};
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_passes::{run_core_passes, run_default_passes, PackageType};
 
 struct Lookup<'a> {
@@ -198,26 +198,26 @@ fn check_intrinsic(file: &str, expr: &str, out: &mut impl Receiver) -> Result<Va
     let core_fir = fir_lowerer.lower_package(&core.package);
     let mut store = PackageStore::new(core);
 
-    let mut std = compile::std(&store, TargetProfile::Full);
+    let mut std = compile::std(&store, RuntimeCapabilityFlags::all());
     assert!(std.errors.is_empty());
     assert!(run_default_passes(
         store.core(),
         &mut std,
         PackageType::Lib,
-        TargetProfile::Full
+        RuntimeCapabilityFlags::all()
     )
     .is_empty());
     let std_fir = fir_lowerer.lower_package(&std.package);
     let std_id = store.insert(std);
 
     let sources = SourceMap::new([("test".into(), file.into())], Some(expr.into()));
-    let mut unit = compile(&store, &[std_id], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[std_id], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty());
     assert!(run_default_passes(
         store.core(),
         &mut unit,
         PackageType::Lib,
-        TargetProfile::Full
+        RuntimeCapabilityFlags::all()
     )
     .is_empty());
     let unit_fir = fir_lowerer.lower_package(&unit.package);
diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs
index 45518899..589fd049 100644
--- a/compiler/qsc_eval/src/tests.rs
+++ b/compiler/qsc_eval/src/tests.rs
@@ -15,7 +15,7 @@ use indoc::indoc;
 use qsc_data_structures::index_map::IndexMap;
 
 use qsc_fir::fir::{BlockId, ExprId, ItemKind, PackageId, PatId, StmtId};
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 
 use qsc_passes::{run_core_passes, run_default_passes, PackageType};
 /// Evaluates the given expression with the given context.
@@ -102,26 +102,26 @@ fn check_expr(file: &str, expr: &str, expect: &Expect) {
     let core_fir = fir_lowerer.lower_package(&core.package);
     let mut store = PackageStore::new(core);
 
-    let mut std = compile::std(&store, TargetProfile::Full);
+    let mut std = compile::std(&store, RuntimeCapabilityFlags::all());
     assert!(std.errors.is_empty());
     assert!(run_default_passes(
         store.core(),
         &mut std,
         PackageType::Lib,
-        TargetProfile::Full
+        RuntimeCapabilityFlags::all()
     )
     .is_empty());
     let std_fir = fir_lowerer.lower_package(&std.package);
     let std_id = store.insert(std);
 
     let sources = SourceMap::new([("test".into(), file.into())], Some(expr.into()));
-    let mut unit = compile(&store, &[std_id], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[std_id], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
     let pass_errors = run_default_passes(
         store.core(),
         &mut unit,
         PackageType::Lib,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(pass_errors.is_empty(), "{pass_errors:?}");
     let unit_fir = fir_lowerer.lower_package(&unit.package);
diff --git a/compiler/qsc_frontend/src/compile/tests.rs b/compiler/qsc_frontend/src/compile/tests.rs
index 184f73ac..40ca42f3 100644
--- a/compiler/qsc_frontend/src/compile/tests.rs
+++ b/compiler/qsc_frontend/src/compile/tests.rs
@@ -3,7 +3,7 @@
 
 #![allow(clippy::needless_raw_string_hashes)]
 
-use crate::compile::TargetProfile;
+use crate::compile::RuntimeCapabilityFlags;
 
 use super::{compile, Error, PackageStore, SourceMap};
 use expect_test::expect;
@@ -71,7 +71,7 @@ fn one_file_no_entry() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 
@@ -100,7 +100,7 @@ fn one_file_error() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     let errors: Vec<_> = unit
         .errors
@@ -143,7 +143,7 @@ fn two_files_dependency() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 }
@@ -182,7 +182,7 @@ fn two_files_mutual_dependency() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 }
@@ -219,7 +219,7 @@ fn two_files_error() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     let errors: Vec<_> = unit
         .errors
@@ -255,7 +255,7 @@ fn entry_call_operation() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 
@@ -294,7 +294,7 @@ fn entry_error() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert_eq!(
         ("<entry>", Span { lo: 4, hi: 5 }),
@@ -336,7 +336,7 @@ fn replace_node() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
     Replacer.visit_package(&mut unit.package);
@@ -419,7 +419,7 @@ fn insert_core_call() {
     );
 
     let store = PackageStore::new(super::core());
-    let mut unit = compile(&store, &[], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
     let mut inserter = Inserter { core: store.core() };
     inserter.visit_package(&mut unit.package);
@@ -465,7 +465,7 @@ fn package_dependency() {
         )],
         None,
     );
-    let unit1 = compile(&store, &[], sources1, TargetProfile::Full);
+    let unit1 = compile(&store, &[], sources1, RuntimeCapabilityFlags::all());
     assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
     let package1 = store.insert(unit1);
 
@@ -483,7 +483,7 @@ fn package_dependency() {
         )],
         None,
     );
-    let unit2 = compile(&store, &[package1], sources2, TargetProfile::Full);
+    let unit2 = compile(&store, &[package1], sources2, RuntimeCapabilityFlags::all());
     assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
 
     expect![[r#"
@@ -526,7 +526,7 @@ fn package_dependency_internal_error() {
         )],
         None,
     );
-    let unit1 = compile(&store, &[], sources1, TargetProfile::Full);
+    let unit1 = compile(&store, &[], sources1, RuntimeCapabilityFlags::all());
     assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
     let package1 = store.insert(unit1);
 
@@ -544,7 +544,7 @@ fn package_dependency_internal_error() {
         )],
         None,
     );
-    let unit2 = compile(&store, &[package1], sources2, TargetProfile::Full);
+    let unit2 = compile(&store, &[package1], sources2, RuntimeCapabilityFlags::all());
 
     let errors: Vec<_> = unit2
         .errors
@@ -594,7 +594,7 @@ fn package_dependency_udt() {
         )],
         None,
     );
-    let unit1 = compile(&store, &[], sources1, TargetProfile::Full);
+    let unit1 = compile(&store, &[], sources1, RuntimeCapabilityFlags::all());
     assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
     let package1 = store.insert(unit1);
 
@@ -612,7 +612,7 @@ fn package_dependency_udt() {
         )],
         None,
     );
-    let unit2 = compile(&store, &[package1], sources2, TargetProfile::Full);
+    let unit2 = compile(&store, &[package1], sources2, RuntimeCapabilityFlags::all());
     assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
 
     expect![[r#"
@@ -657,7 +657,7 @@ fn package_dependency_nested_udt() {
         )],
         None,
     );
-    let unit1 = compile(&store, &[], sources1, TargetProfile::Full);
+    let unit1 = compile(&store, &[], sources1, RuntimeCapabilityFlags::all());
     assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
     let package1 = store.insert(unit1);
 
@@ -680,7 +680,7 @@ fn package_dependency_nested_udt() {
         )],
         None,
     );
-    let unit2 = compile(&store, &[package1], sources2, TargetProfile::Full);
+    let unit2 = compile(&store, &[package1], sources2, RuntimeCapabilityFlags::all());
     assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
 
     expect![[r#"
@@ -735,7 +735,7 @@ fn package_dependency_nested_udt() {
 #[test]
 fn std_dependency() {
     let mut store = PackageStore::new(super::core());
-    let std = store.insert(super::std(&store, TargetProfile::Full));
+    let std = store.insert(super::std(&store, RuntimeCapabilityFlags::all()));
     let sources = SourceMap::new(
         [(
             "test".into(),
@@ -754,14 +754,14 @@ fn std_dependency() {
         Some("Foo.Main()".into()),
     );
 
-    let unit = compile(&store, &[std], sources, TargetProfile::Full);
+    let unit = compile(&store, &[std], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 }
 
 #[test]
 fn std_dependency_base_profile() {
     let mut store = PackageStore::new(super::core());
-    let std = store.insert(super::std(&store, TargetProfile::Base));
+    let std = store.insert(super::std(&store, RuntimeCapabilityFlags::empty()));
     let sources = SourceMap::new(
         [(
             "test".into(),
@@ -780,14 +780,14 @@ fn std_dependency_base_profile() {
         Some("Foo.Main()".into()),
     );
 
-    let unit = compile(&store, &[std], sources, TargetProfile::Base);
+    let unit = compile(&store, &[std], sources, RuntimeCapabilityFlags::empty());
     assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
 }
 
 #[test]
 fn introduce_prelude_ambiguity() {
     let mut store = PackageStore::new(super::core());
-    let std = store.insert(super::std(&store, TargetProfile::Full));
+    let std = store.insert(super::std(&store, RuntimeCapabilityFlags::all()));
     let sources = SourceMap::new(
         [(
             "test".into(),
@@ -802,7 +802,7 @@ fn introduce_prelude_ambiguity() {
         Some("Foo.Main()".into()),
     );
 
-    let unit = compile(&store, &[std], sources, TargetProfile::Full);
+    let unit = compile(&store, &[std], sources, RuntimeCapabilityFlags::all());
     let errors: Vec<Error> = unit.errors;
     assert!(
         errors.len() == 1
@@ -829,7 +829,7 @@ fn entry_parse_error() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
 
     assert_eq!(
@@ -860,7 +860,7 @@ fn two_files_error_eof() {
         &PackageStore::new(super::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     let errors: Vec<_> = unit
         .errors
@@ -895,7 +895,7 @@ fn unimplemented_call_from_dependency_produces_error() {
         None,
     );
     let mut store = PackageStore::new(super::core());
-    let lib = compile(&store, &[], lib_sources, TargetProfile::Full);
+    let lib = compile(&store, &[], lib_sources, RuntimeCapabilityFlags::all());
     assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
     let lib = store.insert(lib);
 
@@ -914,7 +914,7 @@ fn unimplemented_call_from_dependency_produces_error() {
         )],
         None,
     );
-    let unit = compile(&store, &[lib], sources, TargetProfile::Full);
+    let unit = compile(&store, &[lib], sources, RuntimeCapabilityFlags::all());
     expect![[r#"
         [
             Error(
@@ -952,7 +952,7 @@ fn unimplemented_attribute_call_within_unit_error() {
         None,
     );
     let store = PackageStore::new(super::core());
-    let unit = compile(&store, &[], sources, TargetProfile::Full);
+    let unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     expect![[r#"
         [
             Error(
@@ -987,7 +987,7 @@ fn unimplemented_attribute_with_non_unit_expr_error() {
         None,
     );
     let store = PackageStore::new(super::core());
-    let unit = compile(&store, &[], sources, TargetProfile::Full);
+    let unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     expect![[r#"
         [
             Error(
@@ -1022,7 +1022,7 @@ fn unimplemented_attribute_avoids_ambiguous_error_with_duplicate_names_in_scope(
         None,
     );
     let mut store = PackageStore::new(super::core());
-    let lib = compile(&store, &[], lib_sources, TargetProfile::Full);
+    let lib = compile(&store, &[], lib_sources, RuntimeCapabilityFlags::all());
     assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
     let lib = store.insert(lib);
 
@@ -1045,7 +1045,7 @@ fn unimplemented_attribute_avoids_ambiguous_error_with_duplicate_names_in_scope(
         )],
         None,
     );
-    let unit = compile(&store, &[lib], sources, TargetProfile::Full);
+    let unit = compile(&store, &[lib], sources, RuntimeCapabilityFlags::all());
     expect![[r#"
         []
     "#]]
diff --git a/compiler/qsc_frontend/src/incremental/tests.rs b/compiler/qsc_frontend/src/incremental/tests.rs
index 76a746da..d05b2c40 100644
--- a/compiler/qsc_frontend/src/incremental/tests.rs
+++ b/compiler/qsc_frontend/src/incremental/tests.rs
@@ -3,7 +3,7 @@
 
 use super::{Compiler, Increment};
 use crate::{
-    compile::{self, CompileUnit, PackageStore, TargetProfile},
+    compile::{self, CompileUnit, PackageStore, RuntimeCapabilityFlags},
     incremental::Error,
 };
 use expect_test::{expect, Expect};
@@ -14,7 +14,7 @@ use std::fmt::Write;
 #[test]
 fn one_callable() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let unit = compiler
         .compile_fragments(
             &mut CompileUnit::default(),
@@ -62,7 +62,7 @@ fn one_callable() {
 #[test]
 fn one_statement() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let unit = compiler
         .compile_fragments(
             &mut CompileUnit::default(),
@@ -96,7 +96,7 @@ fn one_statement() {
 #[test]
 fn parse_error() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let errors = compiler
         .compile_fragments(&mut CompileUnit::default(), "test_1", "}}", fail_on_error)
         .expect_err("should fail");
@@ -136,7 +136,7 @@ fn parse_error() {
 #[test]
 fn conditional_compilation_not_available() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let errors = compiler
         .compile_fragments(
             &mut CompileUnit::default(),
@@ -159,9 +159,9 @@ fn conditional_compilation_not_available() {
 #[test]
 fn errors_across_multiple_lines() {
     let mut store = PackageStore::new(compile::core());
-    let std = compile::std(&store, TargetProfile::Full);
+    let std = compile::std(&store, RuntimeCapabilityFlags::all());
     let std_id = store.insert(std);
-    let mut compiler = Compiler::new(&store, [std_id], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, [std_id], RuntimeCapabilityFlags::all());
     let mut unit = CompileUnit::default();
     compiler
         .compile_fragments(
@@ -225,7 +225,7 @@ fn errors_across_multiple_lines() {
 #[test]
 fn continue_after_parse_error() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let mut errors = Vec::new();
 
     compiler
@@ -296,7 +296,7 @@ fn continue_after_parse_error() {
 #[test]
 fn continue_after_lower_error() {
     let store = PackageStore::new(compile::core());
-    let mut compiler = Compiler::new(&store, vec![], TargetProfile::Full);
+    let mut compiler = Compiler::new(&store, vec![], RuntimeCapabilityFlags::all());
     let mut unit = CompileUnit::default();
 
     let mut errors = Vec::new();
diff --git a/compiler/qsc_frontend/src/lower/tests.rs b/compiler/qsc_frontend/src/lower/tests.rs
index 7ed3c8f3..d616cc59 100644
--- a/compiler/qsc_frontend/src/lower/tests.rs
+++ b/compiler/qsc_frontend/src/lower/tests.rs
@@ -3,7 +3,7 @@
 
 #![allow(clippy::needless_raw_string_hashes)]
 
-use crate::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use crate::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use expect_test::{expect, Expect};
 use indoc::indoc;
 
@@ -13,7 +13,7 @@ fn check_hir(input: &str, expect: &Expect) {
         &PackageStore::new(compile::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     expect.assert_eq(&unit.package.to_string());
 }
@@ -24,7 +24,7 @@ fn check_errors(input: &str, expect: &Expect) {
         &PackageStore::new(compile::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
 
     let lower_errors: Vec<_> = unit
diff --git a/compiler/qsc_frontend/src/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs
index 342500d8..e601e348 100644
--- a/compiler/qsc_frontend/src/resolve/tests.rs
+++ b/compiler/qsc_frontend/src/resolve/tests.rs
@@ -4,7 +4,7 @@
 #![allow(clippy::needless_raw_string_hashes)]
 
 use super::{Error, Names, Res};
-use crate::{compile, resolve::Resolver};
+use crate::{compile, compile::RuntimeCapabilityFlags, resolve::Resolver};
 use expect_test::{expect, Expect};
 use indoc::indoc;
 use qsc_ast::{
@@ -97,7 +97,7 @@ fn compile(input: &str) -> (Package, Names, Vec<Error>) {
 
     AstAssigner::new().visit_package(&mut package);
 
-    let mut cond_compile = compile::preprocess::Conditional::new(compile::TargetProfile::Full);
+    let mut cond_compile = compile::preprocess::Conditional::new(RuntimeCapabilityFlags::all());
     cond_compile.visit_package(&mut package);
     let dropped_names = cond_compile.into_names();
 
diff --git a/compiler/qsc_passes/src/baseprofck/tests.rs b/compiler/qsc_passes/src/baseprofck/tests.rs
index 9ccb7e5f..941a2d4d 100644
--- a/compiler/qsc_passes/src/baseprofck/tests.rs
+++ b/compiler/qsc_passes/src/baseprofck/tests.rs
@@ -5,15 +5,15 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 
 use crate::baseprofck::check_base_profile_compliance;
 
 fn check(expr: &str, expect: &Expect) {
     let mut store = PackageStore::new(compile::core());
-    let std = store.insert(compile::std(&store, TargetProfile::Full));
+    let std = store.insert(compile::std(&store, RuntimeCapabilityFlags::all()));
     let sources = SourceMap::new([("test".into(), "".into())], Some(expr.into()));
-    let unit = compile(&store, &[std], sources, TargetProfile::Full);
+    let unit = compile(&store, &[std], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
     let errors = check_base_profile_compliance(&unit.package);
diff --git a/compiler/qsc_passes/src/borrowck/tests.rs b/compiler/qsc_passes/src/borrowck/tests.rs
index 8109ecec..5ff5e8f9 100644
--- a/compiler/qsc_passes/src/borrowck/tests.rs
+++ b/compiler/qsc_passes/src/borrowck/tests.rs
@@ -5,7 +5,7 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::visit::Visitor;
 
 use crate::borrowck::Checker;
@@ -13,7 +13,7 @@ use crate::borrowck::Checker;
 fn check(expr: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), "".into())], Some(expr.into()));
-    let unit = compile(&store, &[], sources, TargetProfile::Full);
+    let unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
     let mut borrow_check = Checker::default();
diff --git a/compiler/qsc_passes/src/callable_limits/tests.rs b/compiler/qsc_passes/src/callable_limits/tests.rs
index b7020a08..91a56c46 100644
--- a/compiler/qsc_passes/src/callable_limits/tests.rs
+++ b/compiler/qsc_passes/src/callable_limits/tests.rs
@@ -5,7 +5,7 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::visit::Visitor;
 
 use crate::callable_limits::CallableLimits;
@@ -13,7 +13,7 @@ use crate::callable_limits::CallableLimits;
 fn check(file: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), file.into())], None);
-    let unit = compile(&store, &[], sources, TargetProfile::Full);
+    let unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
     let mut call_limits = CallableLimits::default();
diff --git a/compiler/qsc_passes/src/conjugate_invert/tests.rs b/compiler/qsc_passes/src/conjugate_invert/tests.rs
index 71ab55c8..1fc61152 100644
--- a/compiler/qsc_passes/src/conjugate_invert/tests.rs
+++ b/compiler/qsc_passes/src/conjugate_invert/tests.rs
@@ -6,7 +6,7 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::{validate::Validator, visit::Visitor};
 
 use crate::conjugate_invert::invert_conjugate_exprs;
@@ -14,7 +14,7 @@ use crate::conjugate_invert::invert_conjugate_exprs;
 fn check(file: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), file.into())], None);
-    let mut unit = compile(&store, &[], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
     let errors = invert_conjugate_exprs(store.core(), &mut unit.package, &mut unit.assigner);
diff --git a/compiler/qsc_passes/src/entry_point/tests.rs b/compiler/qsc_passes/src/entry_point/tests.rs
index af88da82..7311337d 100644
--- a/compiler/qsc_passes/src/entry_point/tests.rs
+++ b/compiler/qsc_passes/src/entry_point/tests.rs
@@ -6,7 +6,7 @@
 use crate::entry_point::generate_entry_expr;
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 
 fn check(file: &str, expr: &str, expect: &Expect) {
     let sources = SourceMap::new([("test".into(), file.into())], Some(expr.into()));
@@ -14,7 +14,7 @@ fn check(file: &str, expr: &str, expect: &Expect) {
         &PackageStore::new(compile::core()),
         &[],
         sources,
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
diff --git a/compiler/qsc_passes/src/logic_sep/tests.rs b/compiler/qsc_passes/src/logic_sep/tests.rs
index 775af4af..19e9ebe0 100644
--- a/compiler/qsc_passes/src/logic_sep/tests.rs
+++ b/compiler/qsc_passes/src/logic_sep/tests.rs
@@ -6,7 +6,7 @@
 
 use expect_test::{expect, Expect};
 use qsc_data_structures::span::Span;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::{
     hir::{ExprKind, NodeId, Stmt},
     visit::{walk_stmt, Visitor},
@@ -28,12 +28,12 @@ impl<'a> Visitor<'a> for StmtSpans {
 
 fn check(block_str: &str, expect: &Expect) {
     let mut store = PackageStore::new(compile::core());
-    let std = store.insert(compile::std(&store, TargetProfile::Full));
+    let std = store.insert(compile::std(&store, RuntimeCapabilityFlags::all()));
     let unit = compile(
         &store,
         &[std],
         SourceMap::new([], Some(block_str.into())),
-        TargetProfile::Full,
+        RuntimeCapabilityFlags::all(),
     );
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
diff --git a/compiler/qsc_passes/src/loop_unification/tests.rs b/compiler/qsc_passes/src/loop_unification/tests.rs
index 0c6779a4..4e856339 100644
--- a/compiler/qsc_passes/src/loop_unification/tests.rs
+++ b/compiler/qsc_passes/src/loop_unification/tests.rs
@@ -5,7 +5,7 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::{mut_visit::MutVisitor, validate::Validator, visit::Visitor};
 
 use crate::loop_unification::LoopUni;
@@ -13,7 +13,7 @@ use crate::loop_unification::LoopUni;
 fn check(file: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), file.into())], None);
-    let mut unit = compile(&store, &[], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
     LoopUni {
         core: store.core(),
diff --git a/compiler/qsc_passes/src/replace_qubit_allocation/tests.rs b/compiler/qsc_passes/src/replace_qubit_allocation/tests.rs
index 40f5baba..24c88d06 100644
--- a/compiler/qsc_passes/src/replace_qubit_allocation/tests.rs
+++ b/compiler/qsc_passes/src/replace_qubit_allocation/tests.rs
@@ -4,13 +4,13 @@
 use crate::replace_qubit_allocation::ReplaceQubitAllocation;
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::{mut_visit::MutVisitor, validate::Validator, visit::Visitor};
 
 fn check(file: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), file.into())], None);
-    let mut unit = compile(&store, &[], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
     ReplaceQubitAllocation::new(store.core(), &mut unit.assigner).visit_package(&mut unit.package);
     Validator::default().visit_package(&unit.package);
diff --git a/compiler/qsc_passes/src/spec_gen/tests.rs b/compiler/qsc_passes/src/spec_gen/tests.rs
index 3da1fee6..07dc7594 100644
--- a/compiler/qsc_passes/src/spec_gen/tests.rs
+++ b/compiler/qsc_passes/src/spec_gen/tests.rs
@@ -6,7 +6,7 @@
 
 use expect_test::{expect, Expect};
 use indoc::indoc;
-use qsc_frontend::compile::{self, compile, PackageStore, SourceMap, TargetProfile};
+use qsc_frontend::compile::{self, compile, PackageStore, RuntimeCapabilityFlags, SourceMap};
 use qsc_hir::{validate::Validator, visit::Visitor};
 
 use crate::spec_gen::generate_specs;
@@ -14,7 +14,7 @@ use crate::spec_gen::generate_specs;
 fn check(file: &str, expect: &Expect) {
     let store = PackageStore::new(compile::core());
     let sources = SourceMap::new([("test".into(), file.into())], None);
-    let mut unit = compile(&store, &[], sources, TargetProfile::Full);
+    let mut unit = compile(&store, &[], sources, RuntimeCapabilityFlags::all());
     assert!(unit.errors.is_empty(), "{:?}", unit.errors);
 
     let errors = generate_specs(store.core(), &mut unit.package, &mut unit.assigner);
diff --git a/language_service/src/test_utils.rs b/language_service/src/test_utils.rs
index 7e98aed3..055577d4 100644
--- a/language_service/src/test_utils.rs
+++ b/language_service/src/test_utils.rs
@@ -8,8 +8,8 @@ use crate::{
     protocol::Span,
 };
 use qsc::{
-    compile, hir::PackageId, incremental::Compiler, PackageStore, PackageType, SourceMap,
-    TargetProfile,
+    compile, hir::PackageId, incremental::Compiler, target::Profile, PackageStore, PackageType,
+    SourceMap,
 };
 
 pub(crate) fn compile_with_fake_stdlib_and_markers(
@@ -37,7 +37,7 @@ pub(crate) fn compile_project_with_fake_stdlib_and_markers(
         &[std_package_id],
         source_map,
         PackageType::Exe,
-        TargetProfile::Full,
+        Profile::Unrestricted.into(),
     );
 
     let package_id = package_store.insert(unit);
@@ -84,8 +84,13 @@ where
         None,
     );
 
-    let mut compiler = Compiler::new(false, std_source_map, PackageType::Lib, TargetProfile::Full)
-        .expect("expected incremental compiler creation to succeed");
+    let mut compiler = Compiler::new(
+        false,
+        std_source_map,
+        PackageType::Lib,
+        Profile::Unrestricted.into(),
+    )
+    .expect("expected incremental compiler creation to succeed");
 
     let mut errors = Vec::new();
     for (name, contents) in cells {
@@ -139,7 +144,7 @@ fn compile_fake_stdlib() -> (PackageStore, PackageId) {
         &[PackageId::CORE],
         std_source_map,
         PackageType::Lib,
-        TargetProfile::Full,
+        Profile::Unrestricted.into(),
     );
     assert!(std_errors.is_empty());
     let std_package_id = package_store.insert(std_compile_unit);
diff --git a/language_service/src/tests.rs b/language_service/src/tests.rs
index 2e167618..527a8359 100644
--- a/language_service/src/tests.rs
+++ b/language_service/src/tests.rs
@@ -8,7 +8,7 @@ use crate::{
     LanguageService,
 };
 use expect_test::{expect, Expect};
-use qsc::{compile, PackageType, TargetProfile};
+use qsc::{compile, target::Profile, PackageType};
 use std::{cell::RefCell, sync::Arc};
 
 #[tokio::test]
@@ -245,7 +245,7 @@ async fn target_profile_update_fixes_error() {
     let mut ls = new_language_service(&errors);
 
     ls.update_configuration(&WorkspaceConfigurationUpdate {
-        target_profile: Some(TargetProfile::Base),
+        target_profile: Some(Profile::Base),
         package_type: Some(PackageType::Lib),
     });
 
@@ -303,7 +303,7 @@ async fn target_profile_update_fixes_error() {
     );
 
     ls.update_configuration(&WorkspaceConfigurationUpdate {
-        target_profile: Some(TargetProfile::Full),
+        target_profile: Some(Profile::Unrestricted),
         package_type: None,
     });
 
@@ -342,7 +342,7 @@ async fn target_profile_update_causes_error_in_stdlib() {
     );
 
     ls.update_configuration(&WorkspaceConfigurationUpdate {
-        target_profile: Some(TargetProfile::Base),
+        target_profile: Some(Profile::Base),
         package_type: None,
     });
 
diff --git a/library/tests/src/lib.rs b/library/tests/src/lib.rs
index f401f8c5..9260989b 100644
--- a/library/tests/src/lib.rs
+++ b/library/tests/src/lib.rs
@@ -25,7 +25,8 @@ mod tests;
 
 use qsc::{
     interpret::{stateful, GenericReceiver, Value},
-    PackageType, SourceMap, TargetProfile,
+    target::Profile,
+    PackageType, SourceMap,
 };
 
 /// # Panics
@@ -43,9 +44,13 @@ pub fn test_expression_with_lib(expr: &str, lib: &str, expected: &Value) {
 
     let sources = SourceMap::new([("test".into(), lib.into())], Some(expr.into()));
 
-    let mut interpreter =
-        stateful::Interpreter::new(true, sources, PackageType::Exe, TargetProfile::Full)
-            .expect("test should compile");
+    let mut interpreter = stateful::Interpreter::new(
+        true,
+        sources,
+        PackageType::Exe,
+        Profile::Unrestricted.into(),
+    )
+    .expect("test should compile");
     let result = interpreter
         .eval_entry(&mut out)
         .expect("test should run successfully");
diff --git a/npm/test/basics.js b/npm/test/basics.js
index ccc70639..4d25225f 100644
--- a/npm/test/basics.js
+++ b/npm/test/basics.js
@@ -743,7 +743,7 @@ test("debug service loading source with good entry expr succeeds - web worker",
     const result = await debugService.loadSource(
       "test.qs",
       `namespace Sample { operation Main() : Unit { } }`,
-      "full",
+      "unrestricted",
       "Sample.Main()",
     );
     assert.ok(typeof result === "string");
diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py
index ab60064f..82a46bae 100644
--- a/pip/tests/test_interpreter.py
+++ b/pip/tests/test_interpreter.py
@@ -9,7 +9,7 @@ import pytest
 
 
 def test_output() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     def callback(output):
         nonlocal called
@@ -22,7 +22,7 @@ def test_output() -> None:
 
 
 def test_dump_output() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     def callback(output):
         nonlocal called
@@ -42,8 +42,9 @@ def test_dump_output() -> None:
     )
     assert called
 
+
 def test_dump_machine() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     def callback(output):
         assert output.__repr__() == "STATE:\n|01⟩: 1.0000+0.0000𝑖"
@@ -66,8 +67,9 @@ def test_dump_machine() -> None:
     assert state_dict[1][0] == 1.0
     assert state_dict[1][1] == 0.0
 
+
 def test_error() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     with pytest.raises(QSharpError) as excinfo:
         e.interpret("a864")
@@ -75,7 +77,7 @@ def test_error() -> None:
 
 
 def test_multiple_errors() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     with pytest.raises(QSharpError) as excinfo:
         e.interpret("operation Foo() : Unit { Bar(); Baz(); }")
@@ -84,61 +86,61 @@ def test_multiple_errors() -> None:
 
 
 def test_multiple_statements() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("1; Zero")
     assert value == Result.Zero
 
 
 def test_value_int() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("5")
     assert value == 5
 
 
 def test_value_double() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("3.1")
     assert value == 3.1
 
 
 def test_value_bool() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("true")
     assert value == True
 
 
 def test_value_string() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret('"hello"')
     assert value == "hello"
 
 
 def test_value_result() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("One")
     assert value == Result.One
 
 
 def test_value_pauli() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("PauliX")
     assert value == Pauli.X
 
 
 def test_value_tuple() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret('(1, "hello", One)')
     assert value == (1, "hello", Result.One)
 
 
 def test_value_unit() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("()")
     assert value is None
 
 
 def test_value_array() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
     value = e.interpret("[1, 2, 3]")
     assert value == [1, 2, 3]
 
@@ -159,7 +161,7 @@ def test_qirgen_compile_error() -> None:
 
 
 def test_error_spans_from_multiple_lines() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     # Qsc.Resolve.Ambiguous is chosen as a test case
     # because it contains multiple spans which can be from different lines
@@ -179,7 +181,7 @@ def test_qirgen() -> None:
 
 
 def test_run_with_shots() -> None:
-    e = Interpreter(TargetProfile.Full)
+    e = Interpreter(TargetProfile.Unrestricted)
 
     def callback(output):
         nonlocal called
diff --git a/pip/tests/test_qsharp.py b/pip/tests/test_qsharp.py
index a847629b..67f4d003 100644
--- a/pip/tests/test_qsharp.py
+++ b/pip/tests/test_qsharp.py
@@ -9,7 +9,7 @@ import io
 
 
 def test_stdout() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
     f = io.StringIO()
     with redirect_stdout(f):
         result = qsharp.eval('Message("Hello, world!")')
@@ -19,7 +19,7 @@ def test_stdout() -> None:
 
 
 def test_stdout_multiple_lines() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
     f = io.StringIO()
     with redirect_stdout(f):
         qsharp.eval(
@@ -34,7 +34,7 @@ def test_stdout_multiple_lines() -> None:
 
 
 def test_dump_machine() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
     qsharp.eval(
         """
     use q1 = Qubit();
diff --git a/pip/tests/test_re.py b/pip/tests/test_re.py
index 83680811..5e1fa8c2 100644
--- a/pip/tests/test_re.py
+++ b/pip/tests/test_re.py
@@ -4,8 +4,9 @@
 import qsharp
 from qsharp.estimator import EstimatorParams, QubitParams, QECScheme, LogicalCounts
 
+
 def test_qsharp_estimation() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
     res = qsharp.estimate(
         """{{
         use qs = Qubit[10];
@@ -14,19 +15,23 @@ def test_qsharp_estimation() -> None:
             M(q);
         }}
         }}"""
-        )
+    )
     assert res["status"] == "success"
     assert res["physicalCounts"] is not None
-    assert res.logical_counts == LogicalCounts({
-        'numQubits': 10,
-        'tCount': 10,
-        'rotationCount': 0,
-        'rotationDepth': 0,
-        'cczCount': 0,
-        'measurementCount': 10})
+    assert res.logical_counts == LogicalCounts(
+        {
+            "numQubits": 10,
+            "tCount": 10,
+            "rotationCount": 0,
+            "rotationDepth": 0,
+            "cczCount": 0,
+            "measurementCount": 10,
+        }
+    )
+
 
 def test_qsharp_estimation_from_precalculated_counts() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
     res = qsharp.estimate(
         """{{
         open Microsoft.Quantum.ResourceEstimation;
@@ -36,25 +41,32 @@ def test_qsharp_estimation_from_precalculated_counts() -> None:
             CczCount(3731607428), MeasurementCount(1078154040)],
             PSSPCLayout(), qubits);
         }}"""
-        )
+    )
 
     assert res["status"] == "success"
     assert res["physicalCounts"] is not None
-    assert res.logical_counts == LogicalCounts({
-        'numQubits': 12581,
-        'tCount': 12,
-        'rotationCount': 12,
-        'rotationDepth': 12,
-        'cczCount': 3731607428,
-        'measurementCount': 1078154040})
+    assert res.logical_counts == LogicalCounts(
+        {
+            "numQubits": 12581,
+            "tCount": 12,
+            "rotationCount": 12,
+            "rotationDepth": 12,
+            "cczCount": 3731607428,
+            "measurementCount": 1078154040,
+        }
+    )
+
 
 def test_qsharp_estimation_with_single_params() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
 
     params = EstimatorParams()
     params.error_budget = 0.333
     params.qubit_params.name = QubitParams.MAJ_NS_E4
-    assert params.as_dict() == {'qubitParams': {'name': 'qubit_maj_ns_e4'}, 'errorBudget': 0.333}
+    assert params.as_dict() == {
+        "qubitParams": {"name": "qubit_maj_ns_e4"},
+        "errorBudget": 0.333,
+    }
 
     res = qsharp.estimate(
         """{{
@@ -64,22 +76,26 @@ def test_qsharp_estimation_with_single_params() -> None:
             M(q);
         }}
         }}""",
-        params=params
+        params=params,
     )
 
     assert res["status"] == "success"
     assert res["physicalCounts"] is not None
     assert res["jobParams"]["qubitParams"]["name"] == "qubit_maj_ns_e4"
-    assert res.logical_counts == LogicalCounts({
-        'numQubits': 10,
-        'tCount': 10,
-        'rotationCount': 0,
-        'rotationDepth': 0,
-        'cczCount': 0,
-        'measurementCount': 10})
+    assert res.logical_counts == LogicalCounts(
+        {
+            "numQubits": 10,
+            "tCount": 10,
+            "rotationCount": 0,
+            "rotationDepth": 0,
+            "cczCount": 0,
+            "measurementCount": 10,
+        }
+    )
+
 
 def test_qsharp_estimation_with_multiple_params() -> None:
-    qsharp.init(target_profile=qsharp.TargetProfile.Full)
+    qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
 
     params = EstimatorParams(3)
     params.items[0].qubit_params.name = QubitParams.GATE_US_E3
@@ -89,12 +105,18 @@ def test_qsharp_estimation_with_multiple_params() -> None:
     params.items[2].qubit_params.name = QubitParams.MAJ_NS_E6
     params.items[2].qec_scheme.name = QECScheme.FLOQUET_CODE
     params.items[2].error_budget = 0.333
-    assert params.as_dict() == {'items': [{'qubitParams': {'name': 'qubit_gate_us_e3'}, 'errorBudget': 0.333},
-        {'qubitParams': {'name': 'qubit_gate_us_e4'}, 'errorBudget': 0.333},
-        {'qubitParams': {'name': 'qubit_maj_ns_e6'},
-        'qecScheme': {'name': 'floquet_code'},
-        'errorBudget': 0.333}],
-        'resumeAfterFailedItem': True}
+    assert params.as_dict() == {
+        "items": [
+            {"qubitParams": {"name": "qubit_gate_us_e3"}, "errorBudget": 0.333},
+            {"qubitParams": {"name": "qubit_gate_us_e4"}, "errorBudget": 0.333},
+            {
+                "qubitParams": {"name": "qubit_maj_ns_e6"},
+                "qecScheme": {"name": "floquet_code"},
+                "errorBudget": 0.333,
+            },
+        ],
+        "resumeAfterFailedItem": True,
+    }
 
     res = qsharp.estimate(
         """{{
@@ -104,44 +126,58 @@ def test_qsharp_estimation_with_multiple_params() -> None:
             M(q);
         }}
         }}""",
-        params=params
+        params=params,
     )
 
     for idx in res:
         assert res[idx]["status"] == "success"
         assert res[idx]["physicalCounts"] is not None
-        assert res[idx]["jobParams"]["qubitParams"]["name"] == params.items[idx].qubit_params.name
-        assert res[idx]["logicalCounts"] == LogicalCounts({
-            'numQubits': 10,
-            'tCount': 10,
-            'rotationCount': 0,
-            'rotationDepth': 0,
-            'cczCount': 0,
-            'measurementCount': 10})
+        assert (
+            res[idx]["jobParams"]["qubitParams"]["name"]
+            == params.items[idx].qubit_params.name
+        )
+        assert res[idx]["logicalCounts"] == LogicalCounts(
+            {
+                "numQubits": 10,
+                "tCount": 10,
+                "rotationCount": 0,
+                "rotationDepth": 0,
+                "cczCount": 0,
+                "measurementCount": 10,
+            }
+        )
     assert res[2]["jobParams"]["qecScheme"]["name"] == QECScheme.FLOQUET_CODE
 
+
 def test_estimation_from_logical_counts() -> None:
-    logical_counts = LogicalCounts({
-        'numQubits': 12581,
-        'tCount': 12,
-        'rotationCount': 12,
-        'rotationDepth': 12,
-        'cczCount': 3731607428,
-        'measurementCount': 1078154040})
+    logical_counts = LogicalCounts(
+        {
+            "numQubits": 12581,
+            "tCount": 12,
+            "rotationCount": 12,
+            "rotationDepth": 12,
+            "cczCount": 3731607428,
+            "measurementCount": 1078154040,
+        }
+    )
     res = logical_counts.estimate()
 
     assert res["status"] == "success"
     assert res["physicalCounts"] is not None
     assert res.logical_counts == logical_counts
 
+
 def test_estimation_from_logical_counts_with_single_params() -> None:
-    logical_counts = LogicalCounts({
-        'numQubits': 12581,
-        'tCount': 12,
-        'rotationCount': 12,
-        'rotationDepth': 12,
-        'cczCount': 3731607428,
-        'measurementCount': 1078154040})
+    logical_counts = LogicalCounts(
+        {
+            "numQubits": 12581,
+            "tCount": 12,
+            "rotationCount": 12,
+            "rotationDepth": 12,
+            "cczCount": 3731607428,
+            "measurementCount": 1078154040,
+        }
+    )
     params = EstimatorParams()
     params.error_budget = 0.333
     params.qubit_params.name = QubitParams.MAJ_NS_E4
@@ -152,14 +188,18 @@ def test_estimation_from_logical_counts_with_single_params() -> None:
     assert res["jobParams"]["qubitParams"]["name"] == "qubit_maj_ns_e4"
     assert res.logical_counts == logical_counts
 
+
 def test_estimation_from_logical_counts_with_multiple_params() -> None:
-    logical_counts = LogicalCounts({
-        'numQubits': 12581,
-        'tCount': 12,
-        'rotationCount': 12,
-        'rotationDepth': 12,
-        'cczCount': 3731607428,
-        'measurementCount': 1078154040})
+    logical_counts = LogicalCounts(
+        {
+            "numQubits": 12581,
+            "tCount": 12,
+            "rotationCount": 12,
+            "rotationDepth": 12,
+            "cczCount": 3731607428,
+            "measurementCount": 1078154040,
+        }
+    )
     params = EstimatorParams(3)
     params.items[0].qubit_params.name = QubitParams.GATE_US_E3
     params.items[0].error_budget = 0.333
@@ -173,7 +213,9 @@ def test_estimation_from_logical_counts_with_multiple_params() -> None:
     for idx in res:
         assert res[idx]["status"] == "success"
         assert res[idx]["physicalCounts"] is not None
-        assert res[idx]["jobParams"]["qubitParams"]["name"] == params.items[idx].qubit_params.name
+        assert (
+            res[idx]["jobParams"]["qubitParams"]["name"]
+            == params.items[idx].qubit_params.name
+        )
         assert res[idx]["logicalCounts"] == logical_counts
     assert res[2]["jobParams"]["qecScheme"]["name"] == QECScheme.FLOQUET_CODE
-