From de864270e8e99d26fdecddf6f42a241a5ef67536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C5=9Bkowicz?= Date: Fri, 22 Dec 2023 12:00:24 +0100 Subject: [PATCH] Add support for compiler experimental features commit-id:480c1b28 review update review update fix docs, add todo --- scarb-metadata/src/lib.rs | 3 +++ scarb/src/compiler/db.rs | 9 +++++-- scarb/src/core/manifest/mod.rs | 3 +++ scarb/src/core/manifest/toml_manifest.rs | 5 +++- .../core/publishing/manifest_normalization.rs | 1 + scarb/src/ops/metadata.rs | 10 ++++++++ scarb/tests/metadata.rs | 25 +++++++++++++++++++ .../scarb-test-support/src/project_builder.rs | 13 ++++++++++ website/docs/reference/manifest.md | 9 +++++++ 9 files changed, 75 insertions(+), 3 deletions(-) diff --git a/scarb-metadata/src/lib.rs b/scarb-metadata/src/lib.rs index 5c8bd5f11..3aaf0cdbf 100644 --- a/scarb-metadata/src/lib.rs +++ b/scarb-metadata/src/lib.rs @@ -231,6 +231,9 @@ pub struct PackageMetadata { #[serde(flatten)] pub manifest_metadata: ManifestMetadata, + /// Compiler experimental features allowed for this package. + pub experimental_features: Vec, + /// Additional data not captured by deserializer. #[cfg_attr(feature = "builder", builder(default))] #[serde(flatten)] diff --git a/scarb/src/compiler/db.rs b/scarb/src/compiler/db.rs index 84a2de99a..493694917 100644 --- a/scarb/src/compiler/db.rs +++ b/scarb/src/compiler/db.rs @@ -93,16 +93,21 @@ fn build_project_config(unit: &CompilationUnit) -> Result { .components .iter() .map(|component| { + let experimental_features = component.package.manifest.experimental_features.clone(); ( component.cairo_package_name(), CrateSettings { edition: component.package.manifest.edition, - experimental_features: Default::default(), + // TODO (#1040): replace this with a macro + experimental_features: cairo_lang_filesystem::db::ExperimentalFeaturesConfig { + negative_impls: experimental_features + .unwrap_or_default() + .contains(&SmolStr::new_inline("negative_impls")), + }, }, ) }) .collect(); - let crates_config = AllCratesConfig { override_map: crates_config, ..Default::default() diff --git a/scarb/src/core/manifest/mod.rs b/scarb/src/core/manifest/mod.rs index d33ebdc6f..b3c7d1df2 100644 --- a/scarb/src/core/manifest/mod.rs +++ b/scarb/src/core/manifest/mod.rs @@ -49,6 +49,9 @@ pub struct Manifest { pub compiler_config: ManifestCompilerConfig, #[builder(default)] pub scripts: BTreeMap, + /// Allow experimental features. + #[builder(default)] + pub experimental_features: Option>, } /// Subset of a [`Manifest`] that contains package metadata. diff --git a/scarb/src/core/manifest/toml_manifest.rs b/scarb/src/core/manifest/toml_manifest.rs index 5fbf580cf..4d286f9b0 100644 --- a/scarb/src/core/manifest/toml_manifest.rs +++ b/scarb/src/core/manifest/toml_manifest.rs @@ -198,6 +198,7 @@ pub struct TomlPackage { /// **UNSTABLE** This package does not depend on Cairo's `core`. pub no_core: Option, pub cairo_version: Option>, + pub experimental_features: Option>, } #[derive(Clone, Debug, Serialize, Eq, PartialEq)] @@ -556,6 +557,8 @@ impl TomlManifest { .transpose()? .unwrap_or_default(); + // TODO (#1040): add checking for fields that are not present in ExperimentalFeaturesConfig + let experimental_features = package.experimental_features.clone(); let manifest = ManifestBuilder::default() .summary(summary) .targets(targets) @@ -563,8 +566,8 @@ impl TomlManifest { .metadata(metadata) .compiler_config(compiler_config) .scripts(scripts) + .experimental_features(experimental_features) .build()?; - Ok(manifest) } diff --git a/scarb/src/core/publishing/manifest_normalization.rs b/scarb/src/core/publishing/manifest_normalization.rs index 993534798..6aa3b81c4 100644 --- a/scarb/src/core/publishing/manifest_normalization.rs +++ b/scarb/src/core/publishing/manifest_normalization.rs @@ -75,6 +75,7 @@ fn generate_package(pkg: &Package) -> Box { repository: metadata.repository.clone().map(MaybeWorkspace::Defined), no_core: summary.no_core.then_some(true), cairo_version: metadata.cairo_version.clone().map(MaybeWorkspace::Defined), + experimental_features: pkg.manifest.experimental_features.clone(), }) } diff --git a/scarb/src/ops/metadata.rs b/scarb/src/ops/metadata.rs index 0ec9ab137..008303e9a 100644 --- a/scarb/src/ops/metadata.rs +++ b/scarb/src/ops/metadata.rs @@ -135,6 +135,15 @@ fn collect_package_metadata(package: &Package) -> m::PackageMetadata { let edition = edition_variant(package.manifest.edition); + let experimental_features: Vec = package + .manifest + .experimental_features + .clone() + .unwrap_or_default() + .iter() + .map(|x| x.to_string()) + .collect(); + m::PackageMetadataBuilder::default() .id(wrap_package_id(package.id)) .name(package.id.name.clone()) @@ -146,6 +155,7 @@ fn collect_package_metadata(package: &Package) -> m::PackageMetadata { .dependencies(dependencies) .targets(targets) .manifest_metadata(manifest_metadata) + .experimental_features(experimental_features) .build() .unwrap() } diff --git a/scarb/tests/metadata.rs b/scarb/tests/metadata.rs index 62102cbe1..53196c73c 100644 --- a/scarb/tests/metadata.rs +++ b/scarb/tests/metadata.rs @@ -1287,3 +1287,28 @@ fn includes_edition() { } panic!("Package not found in metadata!"); } + +#[test] +fn includes_experimental_features() { + let t = assert_fs::TempDir::new().unwrap(); + ProjectBuilder::start() + .name("hello") + .version("0.1.0") + .manifest_package_extra(r#"experimental-features = ["negative_impls"]"#) + .build(&t); + + let metadata = Scarb::quick_snapbox() + .arg("--json") + .arg("metadata") + .arg("--format-version") + .arg("1") + .current_dir(&t) + .stdout_json::(); + + assert!(packages_by_name(metadata) + .get("hello") + .unwrap() + .clone() + .experimental_features + .contains(&String::from("negative_impls"))) +} diff --git a/utils/scarb-test-support/src/project_builder.rs b/utils/scarb-test-support/src/project_builder.rs index 8bf4154ee..7f417bd0b 100644 --- a/utils/scarb-test-support/src/project_builder.rs +++ b/utils/scarb-test-support/src/project_builder.rs @@ -24,6 +24,7 @@ pub struct ProjectBuilder { src: HashMap, deps: Vec<(String, Value)>, dev_deps: Vec<(String, Value)>, + manifest_package_extra: String, manifest_extra: String, } @@ -44,6 +45,7 @@ impl ProjectBuilder { )]), deps: Vec::new(), dev_deps: Vec::new(), + manifest_package_extra: String::new(), manifest_extra: String::new(), } } @@ -95,6 +97,11 @@ impl ProjectBuilder { self.dep("starknet", Dep.version(CAIRO_VERSION)) } + pub fn manifest_package_extra(mut self, extra: impl ToString) -> Self { + self.manifest_package_extra = extra.to_string(); + self + } + pub fn manifest_extra(mut self, extra: impl ToString) -> Self { self.manifest_extra = extra.to_string(); self @@ -111,6 +118,12 @@ impl ProjectBuilder { if let Some(cairo_version) = self.cairo_version.as_ref() { doc["package"]["cairo-version"] = Item::Value(Value::from(cairo_version.to_string())); } + let mut manifest = doc.to_string(); + if !self.manifest_package_extra.is_empty() { + manifest.push_str(&self.manifest_package_extra); + } + + let mut doc = manifest.parse::().unwrap(); doc["dependencies"] = toml_edit::table(); for (name, dep) in &self.deps { doc["dependencies"][name.clone()] = Item::Value(dep.clone()); diff --git a/website/docs/reference/manifest.md b/website/docs/reference/manifest.md index c414e6234..e7ad3d820 100644 --- a/website/docs/reference/manifest.md +++ b/website/docs/reference/manifest.md @@ -209,6 +209,15 @@ Keys are human-readable link names, and values are URLs. "We're hiring" = "https://swmansion.com/careers/" ``` +### `experimental-features` + +This field is responsible for setting experimental flags to be used on the package for the compiler. + +```toml +[package] +experimental-features = ["negative_impls"] +``` + ## `[dependencies]` See [Specifying Dependencies](./specifying-dependencies) page.