Repository: microsoft/qsharp
Pull request #896 (2023-12-07 23:54:59)

Remove test profile from qsc_project Cargo.toml
Profile settings are not respected in a child Cargo.toml of a workspace, so these should just be removed.


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/compiler/qsc_project/Cargo.toml b/compiler/qsc_project/Cargo.toml
index 694a3c9b..86ddd675 100644
--- a/compiler/qsc_project/Cargo.toml
+++ b/compiler/qsc_project/Cargo.toml
@@ -25,8 +25,5 @@ qsc_project = { path = ".", features = ["fs"] }
 fs = []
 async = ["async-trait"]
 
-[profile.test]
-default = ["fs"]
-
 [lib]
 doctest = false
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
-