Skip to content

Commit

Permalink
Add support for compiler experimental features in `snforge-test-colle…
Browse files Browse the repository at this point in the history
…ctor` (#1012)
  • Loading branch information
tomek0123456789 authored Jan 16, 2024
1 parent 776ee2f commit ce6ad79
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 14 deletions.
23 changes: 12 additions & 11 deletions extensions/scarb-snforge-test-collector/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::{anyhow, ensure, Context, Result};
use cairo_lang_filesystem::db::{CrateSettings, Edition};
use cairo_lang_filesystem::db::{CrateSettings, Edition, ExperimentalFeaturesConfig};
use cairo_lang_project::AllCratesConfig;
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use camino::{Utf8Path, Utf8PathBuf};
Expand Down Expand Up @@ -109,24 +109,25 @@ impl CompilationUnit<'_> {
.components
.iter()
.map(|component| {
let pkg = self
.metadata
.get_package(&component.package)
.unwrap_or_else(|| panic!("Failed to find = {} package", &component.package));
(
SmolStr::from(&component.name),
CrateSettings {
edition: if let Some(edition) = self
.metadata
.get_package(&component.package)
.unwrap_or_else(|| {
panic!("Failed to find = {} package", component.package)
})
.edition
.clone()
{
edition: if let Some(edition) = pkg.edition.clone() {
let edition_value = serde_json::Value::String(edition);
serde_json::from_value(edition_value).unwrap()
} else {
Edition::default()
},
experimental_features: Default::default(),
// TODO (#1040): replace this with a macro
experimental_features: ExperimentalFeaturesConfig {
negative_impls: pkg
.experimental_features
.contains(&String::from("negative_impls")),
},
},
)
})
Expand Down
3 changes: 3 additions & 0 deletions scarb-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ pub struct PackageMetadata {
#[serde(flatten)]
pub manifest_metadata: ManifestMetadata,

/// Compiler experimental features allowed for this package.
pub experimental_features: Vec<String>,

/// Additional data not captured by deserializer.
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
Expand Down
9 changes: 7 additions & 2 deletions scarb/src/compiler/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,21 @@ fn build_project_config(unit: &CompilationUnit) -> Result<ProjectConfig> {
.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()
Expand Down
3 changes: 3 additions & 0 deletions scarb/src/core/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ pub struct Manifest {
pub compiler_config: ManifestCompilerConfig,
#[builder(default)]
pub scripts: BTreeMap<SmolStr, ScriptDefinition>,
/// Allow experimental features.
#[builder(default)]
pub experimental_features: Option<Vec<SmolStr>>,
}

/// Subset of a [`Manifest`] that contains package metadata.
Expand Down
5 changes: 4 additions & 1 deletion scarb/src/core/manifest/toml_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ pub struct TomlPackage {
/// **UNSTABLE** This package does not depend on Cairo's `core`.
pub no_core: Option<bool>,
pub cairo_version: Option<MaybeWorkspaceField<VersionReq>>,
pub experimental_features: Option<Vec<SmolStr>>,
}

#[derive(Clone, Debug, Serialize, Eq, PartialEq)]
Expand Down Expand Up @@ -556,15 +557,17 @@ 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)
.edition(edition)
.metadata(metadata)
.compiler_config(compiler_config)
.scripts(scripts)
.experimental_features(experimental_features)
.build()?;

Ok(manifest)
}

Expand Down
1 change: 1 addition & 0 deletions scarb/src/core/publishing/manifest_normalization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ fn generate_package(pkg: &Package) -> Box<TomlPackage> {
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(),
})
}

Expand Down
10 changes: 10 additions & 0 deletions scarb/src/ops/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ fn collect_package_metadata(package: &Package) -> m::PackageMetadata {

let edition = edition_variant(package.manifest.edition);

let experimental_features: Vec<String> = 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())
Expand All @@ -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()
}
Expand Down
25 changes: 25 additions & 0 deletions scarb/tests/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,3 +1281,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::<Metadata>();

assert!(packages_by_name(metadata)
.get("hello")
.unwrap()
.clone()
.experimental_features
.contains(&String::from("negative_impls")))
}
13 changes: 13 additions & 0 deletions utils/scarb-test-support/src/project_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct ProjectBuilder {
src: HashMap<Utf8PathBuf, String>,
deps: Vec<(String, Value)>,
dev_deps: Vec<(String, Value)>,
manifest_package_extra: String,
manifest_extra: String,
}

Expand All @@ -44,6 +45,7 @@ impl ProjectBuilder {
)]),
deps: Vec::new(),
dev_deps: Vec::new(),
manifest_package_extra: String::new(),
manifest_extra: String::new(),
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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::<Document>().unwrap();
doc["dependencies"] = toml_edit::table();
for (name, dep) in &self.deps {
doc["dependencies"][name.clone()] = Item::Value(dep.clone());
Expand Down
9 changes: 9 additions & 0 deletions website/docs/reference/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit ce6ad79

Please sign in to comment.