From f730a76aa8d8968d7599a11b3906c186be126720 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Tue, 20 Oct 2026 14:19:00 +0800 Subject: [PATCH 1/2] chore: raise the minimum supported Rust version to 1.88.0 Raise rust-version, the CI MSRV matrix entry, the catalog-check toolchain and the AGENTS.md pre-push gate to 1.88.0, and inline format arguments that Clippy 1.88 flags. Fixes #520 --- .github/workflows/ci.yml | 4 ++-- AGENTS.md | 8 ++++---- Cargo.toml | 2 +- crates/workshop-rs/src/actions/emitter.rs | 3 +-- .../src/bin/workshop-catalog-gen/corpus.rs | 12 +++++------- crates/workshop-rs/src/catalog/load.rs | 3 +-- crates/workshop-rs/src/settings/schema/projection.rs | 3 +-- crates/workshop-rs/src/wir/dump.rs | 2 +- 8 files changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6454e453..c0bac815 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [stable, 1.85.0] + toolchain: [stable, 1.88.0] uses: wrightkit/.github/.github/workflows/rust-quality.yml@main with: toolchain: ${{ matrix.toolchain }} @@ -67,7 +67,7 @@ jobs: - name: Set up Rust uses: wrightkit/.github/.github/actions/setup-rust@main with: - toolchain: 1.85.0 + toolchain: 1.88.0 cache-shared-key: quality - name: Catalog check run: cargo run --locked -p workshop-rs --bin workshop-catalog-gen -- check diff --git a/AGENTS.md b/AGENTS.md index 3aa684c7..0c558033 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -117,10 +117,10 @@ cargo run -p workshop-rs --bin workshop-catalog-gen -- check git diff --check ``` -The workspace declares `rust-version = "1.85.0"`. Before pushing, also run -`cargo +1.85.0 clippy --workspace --all-targets -- -D warnings` and -`cargo +1.85.0 test --workspace --all-targets`; newer syntax such as -let-chains passes on stable and is caught only by the `Rust (1.85.0)` CI job. +The workspace declares `rust-version = "1.88.0"`. Before pushing, also run +`cargo +1.88.0 clippy --workspace --all-targets -- -D warnings` and +`cargo +1.88.0 test --workspace --all-targets`; newer syntax such as +let-chains passes on stable and is caught only by the `Rust (1.88.0)` CI job. A local pass is not proof of live-client behavior. Claims about current Workshop acceptance or seasonal behavior require the corresponding client or diff --git a/Cargo.toml b/Cargo.toml index 4ab7439b..58c5a20e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ resolver = "3" [workspace.package] version = "1.20.0" edition = "2024" -rust-version = "1.85.0" +rust-version = "1.88.0" license = "MIT" repository = "https://github.com/wrightkit/workshop-rs" description = "The canonical multi-locale Overwatch Workshop semantic core." diff --git a/crates/workshop-rs/src/actions/emitter.rs b/crates/workshop-rs/src/actions/emitter.rs index 3535fe1e..96612226 100644 --- a/crates/workshop-rs/src/actions/emitter.rs +++ b/crates/workshop-rs/src/actions/emitter.rs @@ -179,8 +179,7 @@ impl EmitContext<'_> { self.line( level, &format!( - "{}({player_text}, {name}, {start_text}, {stop_text}, {step_text});", - keyword + "{keyword}({player_text}, {name}, {start_text}, {stop_text}, {step_text});" ), )?; for action in body { diff --git a/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs b/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs index 1b904882..e5097c30 100644 --- a/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs +++ b/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs @@ -330,7 +330,7 @@ fn settings_surface(catalog: &Catalog) -> SettingsSurface { } else { enum_spelling(catalog, "Gamemode", &key, &locale).unwrap_or_else(|| key.clone()) }; - (format!("mode.{}.name", key), name) + (format!("mode.{key}.name"), name) }) .collect(); let mut maps = catalog_name_surface(catalog, "Map", "map", &locale); @@ -796,7 +796,7 @@ fn en_aliases(entry: &Value) -> Result, String> { let alias = entry .get("aliases") .and_then(|aliases| aliases.get("en-US")) - .ok_or_else(|| format!("catalog entry '{}' without en-US alias", entry))?; + .ok_or_else(|| format!("catalog entry '{entry}' without en-US alias"))?; match alias { Value::String(spelling) => Ok(vec![spelling.as_str()]), Value::Array(spellings) => { @@ -804,18 +804,16 @@ fn en_aliases(entry: &Value) -> Result, String> { .iter() .map(Value::as_str) .collect::>>() - .ok_or_else(|| format!("catalog entry '{}' with non-string en-US alias", entry))?; + .ok_or_else(|| format!("catalog entry '{entry}' with non-string en-US alias"))?; if spellings.is_empty() { return Err(format!( - "catalog entry '{}' with empty en-US aliases", - entry + "catalog entry '{entry}' with empty en-US aliases" )); } Ok(spellings) } _ => Err(format!( - "catalog entry '{}' with non-string en-US alias", - entry + "catalog entry '{entry}' with non-string en-US alias" )), } } diff --git a/crates/workshop-rs/src/catalog/load.rs b/crates/workshop-rs/src/catalog/load.rs index 52d2551a..b4112bcf 100644 --- a/crates/workshop-rs/src/catalog/load.rs +++ b/crates/workshop-rs/src/catalog/load.rs @@ -128,8 +128,7 @@ impl AliasFile { }; if spellings.is_empty() || spellings.iter().any(String::is_empty) { return Err(CatalogError::validation(format!( - "catalog entry '{}' declares an empty alias for locale '{}'", - id, locale + "catalog entry '{id}' declares an empty alias for locale '{locale}'" ))); } Ok(spellings) diff --git a/crates/workshop-rs/src/settings/schema/projection.rs b/crates/workshop-rs/src/settings/schema/projection.rs index 9d3b1aa8..0993775d 100644 --- a/crates/workshop-rs/src/settings/schema/projection.rs +++ b/crates/workshop-rs/src/settings/schema/projection.rs @@ -484,8 +484,7 @@ pub(super) fn validate_enum_projection( if let Some(previous) = names.insert((domain, name), canonical_member) { if previous != canonical_member { errors.push(format!( - "conflicting settings enum display name {}.{name:?}: {previous} vs {canonical_member}", - domain + "conflicting settings enum display name {domain}.{name:?}: {previous} vs {canonical_member}" )); } } diff --git a/crates/workshop-rs/src/wir/dump.rs b/crates/workshop-rs/src/wir/dump.rs index 8400f6d6..214ac37d 100644 --- a/crates/workshop-rs/src/wir/dump.rs +++ b/crates/workshop-rs/src/wir/dump.rs @@ -391,7 +391,7 @@ fn render_value(program: &Program, id: super::ValueId, out: &mut String) { let value = &node.value; match value { Value::Number { value, .. } => out.push_str(&format_number(*value)), - Value::String(value) => out.push_str(&format!("{:?}", value)), + Value::String(value) => out.push_str(&format!("{value:?}")), Value::LocalizedString(value) => out.push_str(&format!("localized:{value}")), Value::Bool(value) => out.push_str(if *value { "true" } else { "false" }), Value::Null => out.push_str("null"), From ee494554f6261127a86fac809d96ea6cbd42d304 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Tue, 20 Oct 2026 14:31:58 +0800 Subject: [PATCH 2/2] style: collapse nested ifs into let-chains With rust-version 1.88.0, stable Clippy flags collapsible ifs that let-chains now express. --- crates/workshop-rs-cli/src/conformance.rs | 14 +-- crates/workshop-rs-cli/src/live_capture.rs | 12 +-- crates/workshop-rs/src/actions/emitter.rs | 45 ++++----- crates/workshop-rs/src/actions/parser.rs | 7 +- .../src/bin/workshop-catalog-gen/corpus.rs | 20 ++-- .../workshop-rs/src/catalog/descriptions.rs | 14 +-- crates/workshop-rs/src/catalog/mod.rs | 8 +- crates/workshop-rs/src/events/validate.rs | 32 +++--- crates/workshop-rs/src/frontend/lexer.rs | 44 ++++----- crates/workshop-rs/src/frontend/parser.rs | 8 +- crates/workshop-rs/src/lookup.rs | 8 +- crates/workshop-rs/src/output/compare.rs | 34 +++---- crates/workshop-rs/src/program.rs | 17 ++-- .../src/program/conversion/to_wir.rs | 22 ++--- crates/workshop-rs/src/program/source_map.rs | 39 ++++---- crates/workshop-rs/src/settings/check.rs | 8 +- crates/workshop-rs/src/settings/parser.rs | 75 +++++++------- .../src/settings/schema/projection.rs | 99 +++++++++---------- crates/workshop-rs/src/values/emitter.rs | 12 +-- crates/workshop-rs/src/values/parser.rs | 67 ++++++------- crates/workshop-rs/src/values/validate.rs | 97 +++++++++--------- crates/workshop-rs/src/wir/validate.rs | 32 +++--- crates/workshop-rs/tests/common/mod.rs | 44 ++++----- .../workshop-rs/tests/language_conformance.rs | 16 +-- crates/workshop-rs/tests/wir_expansion.rs | 13 ++- 25 files changed, 381 insertions(+), 406 deletions(-) diff --git a/crates/workshop-rs-cli/src/conformance.rs b/crates/workshop-rs-cli/src/conformance.rs index f4786e91..0dfa79ad 100644 --- a/crates/workshop-rs-cli/src/conformance.rs +++ b/crates/workshop-rs-cli/src/conformance.rs @@ -416,13 +416,13 @@ fn validate_artifact( "must identify an immutable revision", )); } - if let Some(digest) = &artifact.sha256 { - if !is_sha256_digest(digest) { - return Err(ConformanceError::invalid( - format!("{field}.sha256"), - "must be a 64-character hexadecimal SHA-256 digest", - )); - } + if let Some(digest) = &artifact.sha256 + && !is_sha256_digest(digest) + { + return Err(ConformanceError::invalid( + format!("{field}.sha256"), + "must be a 64-character hexadecimal SHA-256 digest", + )); } if require_digest && artifact.sha256.is_none() { return Err(ConformanceError::invalid( diff --git a/crates/workshop-rs-cli/src/live_capture.rs b/crates/workshop-rs-cli/src/live_capture.rs index 9cac4f99..030661ed 100644 --- a/crates/workshop-rs-cli/src/live_capture.rs +++ b/crates/workshop-rs-cli/src/live_capture.rs @@ -68,12 +68,12 @@ impl LiveCapture { if normalize_game(&self.catalog.target.game) != normalize_game(&self.game) { return Err(invalid("capture game does not match catalog target game")); } - if let Some(catalog) = catalog { - if self.catalog != catalog.identity() { - return Err(invalid( - "capture catalog identity does not match the loaded catalog", - )); - } + if let Some(catalog) = catalog + && self.catalog != catalog.identity() + { + return Err(invalid( + "capture catalog identity does not match the loaded catalog", + )); } validate_census(&self.census)?; validate_artifact("rawArtifact", &self.raw_artifact, true)?; diff --git a/crates/workshop-rs/src/actions/emitter.rs b/crates/workshop-rs/src/actions/emitter.rs index 96612226..5eb4b773 100644 --- a/crates/workshop-rs/src/actions/emitter.rs +++ b/crates/workshop-rs/src/actions/emitter.rs @@ -323,13 +323,13 @@ impl EmitContext<'_> { if index > 0 { args_text.push_str(", "); } - if index == 0 && player_pair_merged { - if let Some(wir::Value::PlayerVariable { player, variable }) = + if index == 0 + && player_pair_merged + && let Some(wir::Value::PlayerVariable { player, variable }) = self.program.values.get(*arg).map(|node| &node.value) - { - self.emit_variable_pair(*player, *variable, &mut args_text)?; - continue; - } + { + self.emit_variable_pair(*player, *variable, &mut args_text)?; + continue; } let variable_position = match name.as_str() { "setGlobalVariableAtIndex" | "modifyGlobalVariableAtIndex" => { @@ -340,19 +340,17 @@ impl EmitContext<'_> { } _ => false, }; - if variable_position { - if let Some(node) = self.program.values.get(*arg) { - match &node.value { - wir::Value::GlobalVariable(variable) => { - args_text.push_str(self.global_name(*variable)?); - continue; - } - wir::Value::PlayerVariable { variable, .. } => { - args_text.push_str(self.player_name(*variable)?); - continue; - } - _ => {} + if variable_position && let Some(node) = self.program.values.get(*arg) { + match &node.value { + wir::Value::GlobalVariable(variable) => { + args_text.push_str(self.global_name(*variable)?); + continue; } + wir::Value::PlayerVariable { variable, .. } => { + args_text.push_str(self.player_name(*variable)?); + continue; + } + _ => {} } } let operation_name = if matches!( @@ -372,15 +370,14 @@ impl EmitContext<'_> { } else { None }; - if let Some(operation_name) = operation_name { - if self + if let Some(operation_name) = operation_name + && self .catalog .entry(Kind::Operator, &operation_name) .is_some() - { - args_text.push_str(self.spelling(Kind::Operator, &operation_name)?); - continue; - } + { + args_text.push_str(self.spelling(Kind::Operator, &operation_name)?); + continue; } self.value(*arg, &mut args_text)?; } diff --git a/crates/workshop-rs/src/actions/parser.rs b/crates/workshop-rs/src/actions/parser.rs index 44e9bfde..63b3ca3e 100644 --- a/crates/workshop-rs/src/actions/parser.rs +++ b/crates/workshop-rs/src/actions/parser.rs @@ -270,11 +270,10 @@ impl ParseContext<'_> { kind: TokenKind::Word(word), .. }) = self.peek() + && self.settings_name_matches("tokens", "disabled", &word) { - if self.settings_name_matches("tokens", "disabled", &word) { - self.pos += 1; - return true; - } + self.pos += 1; + return true; } false } diff --git a/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs b/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs index e5097c30..359945da 100644 --- a/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs +++ b/crates/workshop-rs/src/bin/workshop-catalog-gen/corpus.rs @@ -806,9 +806,7 @@ fn en_aliases(entry: &Value) -> Result, String> { .collect::>>() .ok_or_else(|| format!("catalog entry '{entry}' with non-string en-US alias"))?; if spellings.is_empty() { - return Err(format!( - "catalog entry '{entry}' with empty en-US aliases" - )); + return Err(format!("catalog entry '{entry}' with empty en-US aliases")); } Ok(spellings) } @@ -1257,10 +1255,10 @@ fn settings_corpus( ); } - if let Ok(previous) = std::fs::read_to_string(settings_out) { - if let Ok(previous) = serde_json::from_str::(&previous) { - preserve_existing_settings(&mut entries, &previous); - } + if let Ok(previous) = std::fs::read_to_string(settings_out) + && let Ok(previous) = serde_json::from_str::(&previous) + { + preserve_existing_settings(&mut entries, &previous); } let mut labels = Map::new(); @@ -1467,10 +1465,10 @@ fn confirmed_settings_identity_match( let mut template_locales = template_translations.as_object()?.clone(); let hero_locales = hero_translations.as_object()?.clone(); for (locale, value) in &mut template_locales { - if let Some(template) = value.as_str() { - if let Some(hero_name) = hero_locales.get(locale).and_then(Value::as_str) { - *value = Value::String(template.replace("%1$s", hero_name)); - } + if let Some(template) = value.as_str() + && let Some(hero_name) = hero_locales.get(locale).and_then(Value::as_str) + { + *value = Value::String(template.replace("%1$s", hero_name)); } } Some(vec![ diff --git a/crates/workshop-rs/src/catalog/descriptions.rs b/crates/workshop-rs/src/catalog/descriptions.rs index 061cfc45..014d66b2 100644 --- a/crates/workshop-rs/src/catalog/descriptions.rs +++ b/crates/workshop-rs/src/catalog/descriptions.rs @@ -226,14 +226,14 @@ fn validated(catalog: &Catalog, file: DescriptionsFile) -> Result "descriptions gap '{key}' names no catalog action or value" )) })?; - if let Gap::Param(_, position) = &gap { - if *position >= catalog.entries[index].params.len() { - return Err(CatalogError::validation(format!( - "descriptions gap '{key}' names parameter {position}, \ + if let Gap::Param(_, position) = &gap + && *position >= catalog.entries[index].params.len() + { + return Err(CatalogError::validation(format!( + "descriptions gap '{key}' names parameter {position}, \ out of {} params", - catalog.entries[index].params.len() - ))); - } + catalog.entries[index].params.len() + ))); } parsed.push(gap); } diff --git a/crates/workshop-rs/src/catalog/mod.rs b/crates/workshop-rs/src/catalog/mod.rs index 5c54f493..29965ee8 100644 --- a/crates/workshop-rs/src/catalog/mod.rs +++ b/crates/workshop-rs/src/catalog/mod.rs @@ -958,10 +958,10 @@ impl Catalog { impl ExpectedDomain for Catalog { fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str> { for kind in [Kind::Action, Kind::Value] { - if let Some(entry) = self.entry(kind, catalog_id) { - if let Some(domain) = entry.param_domain(arg_index) { - return Some(domain); - } + if let Some(entry) = self.entry(kind, catalog_id) + && let Some(domain) = entry.param_domain(arg_index) + { + return Some(domain); } } None diff --git a/crates/workshop-rs/src/events/validate.rs b/crates/workshop-rs/src/events/validate.rs index e7cf1823..7d3c2477 100644 --- a/crates/workshop-rs/src/events/validate.rs +++ b/crates/workshop-rs/src/events/validate.rs @@ -76,25 +76,23 @@ pub(crate) fn validate_event( None } }; - if let Some(target_member) = target_member { - if catalog + if let Some(target_member) = target_member + && catalog .enum_spelling("EventPlayer", &en, &target_member) .is_none() - { - return Err( - WorkshopError::unknown("event player", target_member.clone(), en, span) - .with_candidates(crate::core::suggest::nearest( - &target_member, - catalog - .canonical_member_spellings("EventPlayer", catalog.primary_locale()) - .chain( - catalog - .canonical_member_spellings("Hero", catalog.primary_locale()), - ), - crate::core::suggest::CANDIDATE_LIMIT, - )), - ); - } + { + return Err( + WorkshopError::unknown("event player", target_member.clone(), en, span) + .with_candidates(crate::core::suggest::nearest( + &target_member, + catalog + .canonical_member_spellings("EventPlayer", catalog.primary_locale()) + .chain( + catalog.canonical_member_spellings("Hero", catalog.primary_locale()), + ), + crate::core::suggest::CANDIDATE_LIMIT, + )), + ); } Ok(()) } diff --git a/crates/workshop-rs/src/frontend/lexer.rs b/crates/workshop-rs/src/frontend/lexer.rs index 4e82b390..b5923ef7 100644 --- a/crates/workshop-rs/src/frontend/lexer.rs +++ b/crates/workshop-rs/src/frontend/lexer.rs @@ -110,22 +110,22 @@ pub(crate) fn tokenize(input: &str) -> Result, LexError> { let mut content = String::new(); let mut closed = false; while let Some(c) = cursor.peek() { - if c == '\\' { - if let Some(escaped) = cursor.peek_at(1) { - let decoded = match escaped { - '"' => Some('"'), - '\\' => Some('\\'), - 'n' => Some('\n'), - 'r' => Some('\r'), - 't' => Some('\t'), - _ => None, - }; - if let Some(decoded) = decoded { - cursor.advance(); - cursor.advance(); - content.push(decoded); - continue; - } + if c == '\\' + && let Some(escaped) = cursor.peek_at(1) + { + let decoded = match escaped { + '"' => Some('"'), + '\\' => Some('\\'), + 'n' => Some('\n'), + 'r' => Some('\r'), + 't' => Some('\t'), + _ => None, + }; + if let Some(decoded) = decoded { + cursor.advance(); + cursor.advance(); + content.push(decoded); + continue; } } if c == '"' { @@ -330,13 +330,13 @@ fn take_word(cursor: &mut Cursor) -> Token { let start = cursor.pos(); let mut word = String::new(); while let Some(c) = cursor.peek() { - if c == '<' { - if let Some(len) = markup_tag_len(cursor.rest) { - for _ in 0..len { - word.push(cursor.advance().unwrap()); - } - continue; + if c == '<' + && let Some(len) = markup_tag_len(cursor.rest) + { + for _ in 0..len { + word.push(cursor.advance().unwrap()); } + continue; } let interior_dash = c == '-' && cursor diff --git a/crates/workshop-rs/src/frontend/parser.rs b/crates/workshop-rs/src/frontend/parser.rs index 15fd4bef..2325f488 100644 --- a/crates/workshop-rs/src/frontend/parser.rs +++ b/crates/workshop-rs/src/frontend/parser.rs @@ -605,10 +605,10 @@ impl<'a> ParseContext<'a> { .insert((*id).to_string(), spellings); } for spelling in &self.structural_spellings[*id] { - if let Some(len) = self.match_spelling_tokens(spelling) { - if best.as_ref().is_none_or(|(_, length)| len > *length) { - best = Some(((*id).to_string(), len)); - } + if let Some(len) = self.match_spelling_tokens(spelling) + && best.as_ref().is_none_or(|(_, length)| len > *length) + { + best = Some(((*id).to_string(), len)); } } } diff --git a/crates/workshop-rs/src/lookup.rs b/crates/workshop-rs/src/lookup.rs index 3300c9b4..e84786a7 100644 --- a/crates/workshop-rs/src/lookup.rs +++ b/crates/workshop-rs/src/lookup.rs @@ -722,10 +722,10 @@ fn signature_text( } fn render_default(catalog: &Catalog, locale: &Locale, default: &str) -> String { - if let Some((domain, member)) = default.split_once('.') { - if let Some(member_spelling) = catalog.enum_spelling(domain, locale, member) { - return catalog.enum_member_form(domain, member_spelling, locale); - } + if let Some((domain, member)) = default.split_once('.') + && let Some(member_spelling) = catalog.enum_spelling(domain, locale, member) + { + return catalog.enum_member_form(domain, member_spelling, locale); } catalog .spelling(Kind::Value, locale, default) diff --git a/crates/workshop-rs/src/output/compare.rs b/crates/workshop-rs/src/output/compare.rs index 1d37ae60..709ba12b 100644 --- a/crates/workshop-rs/src/output/compare.rs +++ b/crates/workshop-rs/src/output/compare.rs @@ -1201,23 +1201,23 @@ fn self_modify_inner(pair: SelfModify<'_>, path: &mut Vec) -> Option return Some(difference), - None => { - path.pop(); - } + if let ModifyTarget::Player { player, .. } = pair.target + && let Some(read_player) = read_player + { + // The operand's player receiver must be the action's player. + path.push(PathStep::Value(0)); + let difference = argument_difference( + pair.set_program, + pair.set_program, + path, + 0, + read_player, + player, + ); + match difference { + Some(difference) => return Some(difference), + None => { + path.pop(); } } } diff --git a/crates/workshop-rs/src/program.rs b/crates/workshop-rs/src/program.rs index b6d8cb2d..04556a32 100644 --- a/crates/workshop-rs/src/program.rs +++ b/crates/workshop-rs/src/program.rs @@ -108,10 +108,11 @@ fn prune_spans_outside( document: &SourceDocument, ) { fn prune_slot(slot: &mut Option, file: FileId, document: &SourceDocument) { - if let Some(span) = slot { - if span.file == file && document.byte_range(*span).is_none() { - *slot = None; - } + if let Some(span) = slot + && span.file == file + && document.byte_range(*span).is_none() + { + *slot = None; } } fn prune_value(record: &mut ValueProvenance, file: FileId, document: &SourceDocument) { @@ -657,10 +658,10 @@ impl Program { storage .validate() .map_err(|error| WorkshopError::malformed(error.to_string(), error.span()))?; - if let Some(settings) = &self.settings { - if let Some(error) = crate::settings::check_emission(settings).into_iter().next() { - return Err(error); - } + if let Some(settings) = &self.settings + && let Some(error) = crate::settings::check_emission(settings).into_iter().next() + { + return Err(error); } Ok(()) } diff --git a/crates/workshop-rs/src/program/conversion/to_wir.rs b/crates/workshop-rs/src/program/conversion/to_wir.rs index 73795e33..6b7d3353 100644 --- a/crates/workshop-rs/src/program/conversion/to_wir.rs +++ b/crates/workshop-rs/src/program/conversion/to_wir.rs @@ -467,12 +467,12 @@ fn apply_action_source( let Some(source) = source else { return; }; - if source.identity == action_identity(public) { - if let Some(action) = storage.actions.get_mut(id) { - *action.span_mut() = source.span; - if let Some(identifier) = action.identifier_span_mut() { - *identifier = source.identifier; - } + if source.identity == action_identity(public) + && let Some(action) = storage.actions.get_mut(id) + { + *action.span_mut() = source.span; + if let Some(identifier) = action.identifier_span_mut() { + *identifier = source.identifier; } } let value_ids = storage @@ -500,11 +500,11 @@ fn apply_value_provenance( source: &ValueProvenance, root_identity: NodeIdentity, ) { - if source.identity == root_identity { - if let Some(node) = storage.values.get_mut(value) { - node.span = source.span; - node.identifier = source.identifier; - } + if source.identity == root_identity + && let Some(node) = storage.values.get_mut(value) + { + node.span = source.span; + node.identifier = source.identifier; } let public_children = value_children(public); if source.children.len() != public_children.len() { diff --git a/crates/workshop-rs/src/program/source_map.rs b/crates/workshop-rs/src/program/source_map.rs index 29f2cfde..1a023c75 100644 --- a/crates/workshop-rs/src/program/source_map.rs +++ b/crates/workshop-rs/src/program/source_map.rs @@ -199,18 +199,17 @@ impl SourceMap { &mut spans, ); for (rule, public) in program.rules.iter().enumerate() { - if let Some(provenance) = program.rule_provenance(rule) { - if provenance.span.is_some() + if let Some(provenance) = program.rule_provenance(rule) + && (provenance.span.is_some() || provenance.name.is_some() - || provenance.event_name.is_some() - { - spans.push(MappedNode::Rule { - rule, - span: provenance.span.map(WireSpan::from), - name_span: provenance.name.map(WireSpan::from), - event_name_span: provenance.event_name.map(WireSpan::from), - }); - } + || provenance.event_name.is_some()) + { + spans.push(MappedNode::Rule { + rule, + span: provenance.span.map(WireSpan::from), + name_span: provenance.name.map(WireSpan::from), + event_name_span: provenance.event_name.map(WireSpan::from), + }); } for (condition, public_condition) in public.conditions.iter().enumerate() { let Some(record) = program.condition_record(rule, condition) else { @@ -235,15 +234,15 @@ impl SourceMap { } } for (action, public_action) in public.actions.iter().enumerate() { - if let Some(provenance) = program.action_provenance(rule, action) { - if provenance.span.is_some() || provenance.identifier.is_some() { - spans.push(MappedNode::Action { - rule, - action, - span: provenance.span.map(WireSpan::from), - identifier_span: provenance.identifier.map(WireSpan::from), - }); - } + if let Some(provenance) = program.action_provenance(rule, action) + && (provenance.span.is_some() || provenance.identifier.is_some()) + { + spans.push(MappedNode::Action { + rule, + action, + span: provenance.span.map(WireSpan::from), + identifier_span: provenance.identifier.map(WireSpan::from), + }); } for (argument, value) in action_argument_values(public_action) .iter() diff --git a/crates/workshop-rs/src/settings/check.rs b/crates/workshop-rs/src/settings/check.rs index cb1dd2b5..22a93deb 100644 --- a/crates/workshop-rs/src/settings/check.rs +++ b/crates/workshop-rs/src/settings/check.rs @@ -338,10 +338,10 @@ fn check_member(node: &SettingsNode, path: &[PathPart<'_>], errors: &mut Vec return, diff --git a/crates/workshop-rs/src/settings/parser.rs b/crates/workshop-rs/src/settings/parser.rs index 8ea9da7a..e16e7324 100644 --- a/crates/workshop-rs/src/settings/parser.rs +++ b/crates/workshop-rs/src/settings/parser.rs @@ -86,11 +86,10 @@ impl ParseContext<'_> { kind: TokenKind::Word(word), .. }) = self.peek() + && self.settings_name_matches("tokens", "disabled", &word) { - if self.settings_name_matches("tokens", "disabled", &word) { - self.pos += 1; - disabled = true; - } + self.pos += 1; + disabled = true; } if !disabled { // Multi-token disabled prefixes (`Devre Dışı`, @@ -818,10 +817,10 @@ impl ParseContext<'_> { display: &str, hero: Option<&str>, ) -> bool { - if let Some(PathPart::Part(key)) = candidate.path.last() { - if table::names_eq(display, key) { - return true; - } + if let Some(PathPart::Part(key)) = candidate.path.last() + && table::names_eq(display, key) + { + return true; } if let (Some(hero), Some(PathPart::Part(key))) = (hero, candidate.path.last()) { if table::hero_setting_name(hero, key, self.locale.as_str()) @@ -854,40 +853,40 @@ impl ParseContext<'_> { PathPart::Part(key) if !aliased => Some(*key), _ => None, }); - if let Some(key) = unshadowed_key { - if let Some(template) = table::hero_key_template(key).or_else(|| { + if let Some(key) = unshadowed_key + && let Some(template) = table::hero_key_template(key).or_else(|| { candidate .workshop_name .contains("%1$s") .then_some(candidate.workshop_name) - }) { - // A `%1$s`-only template substitutes to the bare - // ability name; longer templates (`%1$s Cooldown - // Time`) must not bind it (#448). The producer fills - // the locale's template spelling when one exists - // (`Tempo de recarga de %1$s`), and mixed-locale - // sources may carry the en-US form. - let ability_name = |locale: &str| { - crate::gameplay::data::builtin_ref() - .ok()? - .query() - .ability_name(hero, slot, None, locale) - .ok() - .map(str::to_string) - }; - let substitute = |template: &str, name: &str| { - table::names_eq(template.replace("%1$s", name).as_str(), display) - }; - let localized_template = - table::localized_name(self.locale.as_str(), "labels", template) - .unwrap_or(template); - let matched = ability_name(self.locale.as_str()).is_some_and(|name| { - substitute(localized_template, &name) || substitute(template, &name) - }) || (self.locale.as_str() != "en-US" - && ability_name("en-US").is_some_and(|name| substitute(template, &name))); - if matched { - return true; - } + }) + { + // A `%1$s`-only template substitutes to the bare + // ability name; longer templates (`%1$s Cooldown + // Time`) must not bind it (#448). The producer fills + // the locale's template spelling when one exists + // (`Tempo de recarga de %1$s`), and mixed-locale + // sources may carry the en-US form. + let ability_name = |locale: &str| { + crate::gameplay::data::builtin_ref() + .ok()? + .query() + .ability_name(hero, slot, None, locale) + .ok() + .map(str::to_string) + }; + let substitute = |template: &str, name: &str| { + table::names_eq(template.replace("%1$s", name).as_str(), display) + }; + let localized_template = + table::localized_name(self.locale.as_str(), "labels", template) + .unwrap_or(template); + let matched = ability_name(self.locale.as_str()).is_some_and(|name| { + substitute(localized_template, &name) || substitute(template, &name) + }) || (self.locale.as_str() != "en-US" + && ability_name("en-US").is_some_and(|name| substitute(template, &name))); + if matched { + return true; } } } diff --git a/crates/workshop-rs/src/settings/schema/projection.rs b/crates/workshop-rs/src/settings/schema/projection.rs index 0993775d..fde165d9 100644 --- a/crates/workshop-rs/src/settings/schema/projection.rs +++ b/crates/workshop-rs/src/settings/schema/projection.rs @@ -290,18 +290,18 @@ pub fn validate_catalog() -> Result<(), Vec> { let target_kind = definition.target_kind(); let semantic_key = semantic_identity_key(definition.key); let collision_key = (id.as_str().to_string(), target_kind.clone()); - if let Some(previous_key) = concept_keys.insert(collision_key, semantic_key.clone()) { - if previous_key != semantic_key { - errors.push(format!( - "conflicting settings concepts for {id}: {previous_key} vs {semantic_key}" - )); - } + if let Some(previous_key) = concept_keys.insert(collision_key, semantic_key.clone()) + && previous_key != semantic_key + { + errors.push(format!( + "conflicting settings concepts for {id}: {previous_key} vs {semantic_key}" + )); } let key = (id.as_str().to_string(), target_kind, semantic_key); - if let Some(previous) = concepts.insert(key, definition.domain.clone()) { - if previous != definition.domain { - errors.push(format!("conflicting settings domains for {id}")); - } + if let Some(previous) = concepts.insert(key, definition.domain.clone()) + && previous != definition.domain + { + errors.push(format!("conflicting settings domains for {id}")); } } if errors.is_empty() { @@ -320,21 +320,20 @@ pub(super) fn validate_raw_projection( let mut paths = HashMap::new(); for projected in entries { let entry = projected.entry; - if let Some(previous) = paths.insert(entry.path, projected) { - if previous.entry != entry - && !reconciled_entry_override( - table::path_string(entry.path).as_str(), - previous, - projected, - ) - { - errors.push(format!( - "conflicting duplicate settings path between {} and {}: {}", - previous.source.label(), - projected.source.label(), - table::path_string(entry.path), - )); - } + if let Some(previous) = paths.insert(entry.path, projected) + && previous.entry != entry + && !reconciled_entry_override( + table::path_string(entry.path).as_str(), + previous, + projected, + ) + { + errors.push(format!( + "conflicting duplicate settings path between {} and {}: {}", + previous.source.label(), + projected.source.label(), + table::path_string(entry.path), + )); } } errors @@ -403,21 +402,21 @@ pub(super) fn validate_enum_projection( errors.push(format!("orphaned settings enum domain: {}", member.domain)); } let key = (member.domain, member.member); - if let Some(previous) = members.insert(key, member.name) { - if previous != member.name { - errors.push(format!( - "conflicting settings enum member {}.{}: {previous:?} vs {:?}", - member.domain, member.member, member.name - )); - } + if let Some(previous) = members.insert(key, member.name) + && previous != member.name + { + errors.push(format!( + "conflicting settings enum member {}.{}: {previous:?} vs {:?}", + member.domain, member.member, member.name + )); } - if let Some(previous) = names.insert((member.domain, member.name), member.member) { - if previous != member.member { - errors.push(format!( - "conflicting settings enum display name {}.{:?}: {previous} vs {}", - member.domain, member.name, member.member - )); - } + if let Some(previous) = names.insert((member.domain, member.name), member.member) + && previous != member.member + { + errors.push(format!( + "conflicting settings enum display name {}.{:?}: {previous} vs {}", + member.domain, member.name, member.member + )); } } let fixture_members: HashMap<_, _> = table::ENUM_MEMBERS @@ -427,13 +426,13 @@ pub(super) fn validate_enum_projection( let mut mapped_sources = HashSet::new(); for member in generated_entries { let key = (member.domain, member.member); - if let Some(previous) = members.insert(key, member.name) { - if previous != member.name { - errors.push(format!( - "conflicting settings enum member {}.{}: {previous:?} vs {:?}", - member.domain, member.member, member.name - )); - } + if let Some(previous) = members.insert(key, member.name) + && previous != member.name + { + errors.push(format!( + "conflicting settings enum member {}.{}: {previous:?} vs {:?}", + member.domain, member.member, member.name + )); } let mapping = mappings.iter().find(|mapping| { mapping.source_domain == member.domain && mapping.source_member == member.member @@ -481,12 +480,12 @@ pub(super) fn validate_enum_projection( } None => (member.domain, member.member, member.name), }; - if let Some(previous) = names.insert((domain, name), canonical_member) { - if previous != canonical_member { - errors.push(format!( + if let Some(previous) = names.insert((domain, name), canonical_member) + && previous != canonical_member + { + errors.push(format!( "conflicting settings enum display name {domain}.{name:?}: {previous} vs {canonical_member}" )); - } } } for mapping in mappings { diff --git a/crates/workshop-rs/src/values/emitter.rs b/crates/workshop-rs/src/values/emitter.rs index 8f8369d3..ee97b3c3 100644 --- a/crates/workshop-rs/src/values/emitter.rs +++ b/crates/workshop-rs/src/values/emitter.rs @@ -458,13 +458,13 @@ impl<'a> EmitContext<'a> { if let Some(spelling) = resolve(&self.locale) { return Ok(spelling); } - if let Some(fallback) = &self.fallback { - if let Some(spelling) = resolve(fallback) { - if !dedup || !self.fallback_ids.contains(&fallback_id) { - self.fallback_ids.push(fallback_id); - } - return Ok(spelling); + if let Some(fallback) = &self.fallback + && let Some(spelling) = resolve(fallback) + { + if !dedup || !self.fallback_ids.contains(&fallback_id) { + self.fallback_ids.push(fallback_id); } + return Ok(spelling); } Err(WorkshopError::MissingMapping { kind, diff --git a/crates/workshop-rs/src/values/parser.rs b/crates/workshop-rs/src/values/parser.rs index 37c5db26..2c5c18c4 100644 --- a/crates/workshop-rs/src/values/parser.rs +++ b/crates/workshop-rs/src/values/parser.rs @@ -237,22 +237,19 @@ impl ParseContext<'_> { kind: TokenKind::Word(next), .. }) = self.peek() + && (canonical_keyword(&next) == "Variable" + || canonical_keyword(&next) == "variable") { - if canonical_keyword(&next) == "Variable" - || canonical_keyword(&next) == "variable" - { - self.pos += 1; - self.expect(TokenKind::LParen, "expected '(' after 'Global Variable'")?; - let (name, name_start, name_end) = self.phrase()?; - let variable = self.global_by_name(&name)?; - self.expect(TokenKind::RParen, "expected ')' after Global Variable")?; - let span = Some(Span::new(self.file(), start, end)); - return Ok(self.target.values.push( - ValueNode::new(Value::GlobalVariable(variable), span).with_identifier( - Some(Span::new(self.file(), name_start, name_end)), - ), - )); - } + self.pos += 1; + self.expect(TokenKind::LParen, "expected '(' after 'Global Variable'")?; + let (name, name_start, name_end) = self.phrase()?; + let variable = self.global_by_name(&name)?; + self.expect(TokenKind::RParen, "expected ')' after Global Variable")?; + let span = Some(Span::new(self.file(), start, end)); + return Ok(self.target.values.push( + ValueNode::new(Value::GlobalVariable(variable), span) + .with_identifier(Some(Span::new(self.file(), name_start, name_end))), + )); } self.expect(TokenKind::Dot, "expected '.' after 'Global'")?; let (name, name_start, name_end) = self.phrase()?; @@ -516,10 +513,8 @@ impl ParseContext<'_> { let prefer_enum = self.catalog.enum_domain("Hero").is_some() && (canonical_keyword(phrase) == "Hero" || self.resolve_enum_domain_mixed(phrase) == Some("Hero")); - if !prefer_enum { - if let Some(entry) = self.resolve_entry(Kind::Value, phrase) { - return self.value_call(entry, phrase, start, end); - } + if !prefer_enum && let Some(entry) = self.resolve_entry(Kind::Value, phrase) { + return self.value_call(entry, phrase, start, end); } // An action spelling can collide with an enum domain (`Wait` is // both). The enum reading only stands when the call actually parses @@ -545,10 +540,10 @@ impl ParseContext<'_> { // emits `英雄(英雄(D.Va))` for `hero(Hero.DVA)` (#448). if prefer_enum { self.pos = saved; - if let Some(entry) = self.resolve_entry(Kind::Value, phrase) { - if let Ok(value) = self.value_call(entry, phrase, start, end) { - return Ok(value); - } + if let Some(entry) = self.resolve_entry(Kind::Value, phrase) + && let Ok(value) = self.value_call(entry, phrase, start, end) + { + return Ok(value); } self.pos = saved; } @@ -833,22 +828,20 @@ impl ParseContext<'_> { .call_stack .last() .is_some_and(|call| call == "createHudText") + && let Some((value_type, value)) = self.resolve_enum_member_mixed("HudPosition", phrase) { - if let Some((value_type, value)) = self.resolve_enum_member_mixed("HudPosition", phrase) - { - return Ok(self.target.values.push(ValueNode::new( - Value::Enum { value_type, value }, - Some(Span::new(self.file(), start, end)), - ))); - } + return Ok(self.target.values.push(ValueNode::new( + Value::Enum { value_type, value }, + Some(Span::new(self.file(), start, end)), + ))); } - if matches!(self.expected_domain, Some("Position")) { - if let Some((value_type, value)) = self.resolve_enum_member_mixed("Vector", phrase) { - return Ok(self.target.values.push(ValueNode::new( - Value::Enum { value_type, value }, - Some(Span::new(self.file(), start, end)), - ))); - } + if matches!(self.expected_domain, Some("Position")) + && let Some((value_type, value)) = self.resolve_enum_member_mixed("Vector", phrase) + { + return Ok(self.target.values.push(ValueNode::new( + Value::Enum { value_type, value }, + Some(Span::new(self.file(), start, end)), + ))); } // Event filter domains are resolved by the event parser and are not // value-argument domains. Excluding them here keeps their spellings diff --git a/crates/workshop-rs/src/values/validate.rs b/crates/workshop-rs/src/values/validate.rs index 5fa13137..9fa7db4c 100644 --- a/crates/workshop-rs/src/values/validate.rs +++ b/crates/workshop-rs/src/values/validate.rs @@ -41,10 +41,10 @@ pub(crate) fn validate_value( node.span, )); } - } else if !wir::is_canonical_helper_call(name, args.len()) { - if let Some(entry) = catalog.entry(Kind::Value, name) { - validate_call_signature(entry, args, node.span, program, catalog)?; - } + } else if !wir::is_canonical_helper_call(name, args.len()) + && let Some(entry) = catalog.entry(Kind::Value, name) + { + validate_call_signature(entry, args, node.span, program, catalog)?; } } else if !tolerate_residuals { return Err(WorkshopError::unknown( @@ -237,14 +237,14 @@ pub(crate) fn validate_call_signature( program.values.get(*arg_id).and_then(|node| node.span), )); } - if index == 0 && player_pair_folded { - if let Some(wir::ValueNode { + if index == 0 + && player_pair_folded + && let Some(wir::ValueNode { value: wir::Value::PlayerVariable { player, .. }, .. }) = program.values.get(*arg_id) - { - validate_call_argument(entry, 0, *player, program, catalog)?; - } + { + validate_call_argument(entry, 0, *player, program, catalog)?; } validate_call_argument( entry, @@ -264,23 +264,22 @@ fn validate_call_argument( program: &wir::Program, catalog: &Catalog, ) -> Result<()> { - if let Some(expected) = entry.param_type(index) { - if !value_matches_type(program, catalog, arg_id, expected) - && !contextual_value_matches(entry, index, program, arg_id, expected) - { - let actual = value_type_name(program, catalog, arg_id); - return Err(WorkshopError::unsupported( - format!( - "{} '{}' argument {} must have semantic type '{}', got {}", - entry.kind.as_str(), - entry.id, - index + 1, - expected, - actual - ), - program.values.get(arg_id).and_then(|node| node.span), - )); - } + if let Some(expected) = entry.param_type(index) + && !value_matches_type(program, catalog, arg_id, expected) + && !contextual_value_matches(entry, index, program, arg_id, expected) + { + let actual = value_type_name(program, catalog, arg_id); + return Err(WorkshopError::unsupported( + format!( + "{} '{}' argument {} must have semantic type '{}', got {}", + entry.kind.as_str(), + entry.id, + index + 1, + expected, + actual + ), + program.values.get(arg_id).and_then(|node| node.span), + )); } let Some(domain) = entry.param_domain(index) else { return Ok(()); @@ -413,30 +412,28 @@ fn value_matches_type( if expected.split('|').next() == Some("Boolean") { return true; } - if let wir::Value::Call { name, .. } = &node.value { - if name == wir::AMBIGUOUS_ENUM_CALL { - return expected.split('|').any(|alternative| { - matches!(alternative, "Any" | "Unknown" | "Object") - || wir::ambiguous_enum_parts(program, value_id).is_some_and( - |(_, candidate_ids)| { - candidate_ids.iter().any(|candidate_id| { - matches!( - program.values.get(*candidate_id), - Some(wir::ValueNode { - value: wir::Value::Enum { value_type, value }, - .. - }) if enum_type_matches_domain( - catalog, - value_type, - value, - alternative, - ) - ) - }) - }, - ) - }); - } + if let wir::Value::Call { name, .. } = &node.value + && name == wir::AMBIGUOUS_ENUM_CALL + { + return expected.split('|').any(|alternative| { + matches!(alternative, "Any" | "Unknown" | "Object") + || wir::ambiguous_enum_parts(program, value_id).is_some_and(|(_, candidate_ids)| { + candidate_ids.iter().any(|candidate_id| { + matches!( + program.values.get(*candidate_id), + Some(wir::ValueNode { + value: wir::Value::Enum { value_type, value }, + .. + }) if enum_type_matches_domain( + catalog, + value_type, + value, + alternative, + ) + ) + }) + }) + }); } expected .split('|') diff --git a/crates/workshop-rs/src/wir/validate.rs b/crates/workshop-rs/src/wir/validate.rs index 8fb06d20..44b327d4 100644 --- a/crates/workshop-rs/src/wir/validate.rs +++ b/crates/workshop-rs/src/wir/validate.rs @@ -43,14 +43,14 @@ fn check_rule(program: &Program, rule: &Rule) -> Result<(), IrError> { Event::EachPlayerWithFilters { target, .. } | Event::Player { target, .. } => Some(target), _ => None, }; - if let Some(EventTarget::Slot(slot)) = target { - if *slot > 11 { - return Err(IrError::Invalid { - code: "invalid-event-slot", - message: format!("event slot {slot} is outside the canonical 0..=11 range"), - span: rule.span, - }); - } + if let Some(EventTarget::Slot(slot)) = target + && *slot > 11 + { + return Err(IrError::Invalid { + code: "invalid-event-slot", + message: format!("event slot {slot} is outside the canonical 0..=11 range"), + span: rule.span, + }); } for condition in &rule.conditions { check_value(program, condition.value)?; @@ -267,14 +267,14 @@ fn check_span(span: Option, program: &Program) -> Result<(), IrError> { span: Some(span), }); } - if let Some(source) = program.files.get(span.file).and_then(|file| file.source()) { - if source.byte_range(span).is_none() { - return Err(IrError::Invalid { - code: "invalid-span", - message: "span is outside its retained source document".into(), - span: Some(span), - }); - } + if let Some(source) = program.files.get(span.file).and_then(|file| file.source()) + && source.byte_range(span).is_none() + { + return Err(IrError::Invalid { + code: "invalid-span", + message: "span is outside its retained source document".into(), + span: Some(span), + }); } Ok(()) } diff --git a/crates/workshop-rs/tests/common/mod.rs b/crates/workshop-rs/tests/common/mod.rs index 79d49518..d04280e4 100644 --- a/crates/workshop-rs/tests/common/mod.rs +++ b/crates/workshop-rs/tests/common/mod.rs @@ -242,39 +242,35 @@ pub(crate) fn assert_target_locale_spellings( if let (Some(source_spelling), Some(target_spelling)) = ( domain.spelling(source_locale), domain.spelling(target_locale), - ) { - if source_spelling != target_spelling - && canonical_uses(&domain.domain) + ) && source_spelling != target_spelling + && canonical_uses(&domain.domain) + && source.contains(source_spelling) + { + assert!( + target.contains(target_spelling), + "{name} target locale omitted enum domain '{}' spelling '{}', source spelling '{}' remains the only evidence", + domain.domain, + target_spelling, + source_spelling + ); + } + for member in &domain.members { + if let (Some(source_spelling), Some(target_spelling)) = ( + member.spelling(source_locale), + member.spelling(target_locale), + ) && source_spelling != target_spelling + && canonical_uses(&member.member) && source.contains(source_spelling) { assert!( target.contains(target_spelling), - "{name} target locale omitted enum domain '{}' spelling '{}', source spelling '{}' remains the only evidence", + "{name} target locale omitted enum member '{}.{}' spelling '{}', source spelling '{}' remains the only evidence", domain.domain, + member.member, target_spelling, source_spelling ); } } - for member in &domain.members { - if let (Some(source_spelling), Some(target_spelling)) = ( - member.spelling(source_locale), - member.spelling(target_locale), - ) { - if source_spelling != target_spelling - && canonical_uses(&member.member) - && source.contains(source_spelling) - { - assert!( - target.contains(target_spelling), - "{name} target locale omitted enum member '{}.{}' spelling '{}', source spelling '{}' remains the only evidence", - domain.domain, - member.member, - target_spelling, - source_spelling - ); - } - } - } } } diff --git a/crates/workshop-rs/tests/language_conformance.rs b/crates/workshop-rs/tests/language_conformance.rs index bdeb8fb7..dcef9b4e 100644 --- a/crates/workshop-rs/tests/language_conformance.rs +++ b/crates/workshop-rs/tests/language_conformance.rs @@ -618,10 +618,10 @@ fn call_program_source_variant( if entry.id == "string" { args[0] = "\"Hello\"".to_string(); } - if let Some((index, argument)) = override_argument { - if let Some(slot) = args.get_mut(index) { - *slot = argument; - } + if let Some((index, argument)) = override_argument + && let Some(slot) = args.get_mut(index) + { + *slot = argument; } if extra_argument { args.push("True".to_string()); @@ -1047,13 +1047,13 @@ fn assert_documented_contract( entry.params().get(index) )); } - if let Some(value_type) = parameter.value_type.as_deref() { - if entry.param_type(index) != Some(value_type) { - failures.push(format!( + if let Some(value_type) = parameter.value_type.as_deref() + && entry.param_type(index) != Some(value_type) + { + failures.push(format!( "{case_id}: documented parameter {index} type {value_type:?} differs from catalog {:?}", entry.param_type(index) )); - } } } match kind { diff --git a/crates/workshop-rs/tests/wir_expansion.rs b/crates/workshop-rs/tests/wir_expansion.rs index d5b78bb9..e8c2e465 100644 --- a/crates/workshop-rs/tests/wir_expansion.rs +++ b/crates/workshop-rs/tests/wir_expansion.rs @@ -414,10 +414,9 @@ fn unknown_enum_member_is_rejected() { if let Value::Enum { value_type, value, .. } = &node.value + && value_type == "Color" { - if value_type == "Color" { - let _ = value; - } + let _ = value; } } let color_id = program @@ -441,10 +440,10 @@ fn unknown_enum_member_is_rejected() { fn unknown_value_id_is_rejected() { let mut program = build_surface_program(); for node in program.values.iter() { - if let Value::Call { name, .. } = &node.value { - if name == "add" { - let _ = name; - } + if let Value::Call { name, .. } = &node.value + && name == "add" + { + let _ = name; } } let add_id = program