From a683e510451f80c01ba37acebdaae76ec7eb934c Mon Sep 17 00:00:00 2001 From: bflatastic Date: Mon, 26 Oct 2026 23:31:15 +0700 Subject: [PATCH] #726: Dart names never shadow Dart types (classes and constants) --- crates/engine/src/cmd/variables_io.rs | 13 +++++++++++-- crates/engine/src/variables_io_tests.rs | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/variables_io.rs b/crates/engine/src/cmd/variables_io.rs index 853209f4..dd48dca6 100644 --- a/crates/engine/src/cmd/variables_io.rs +++ b/crates/engine/src/cmd/variables_io.rs @@ -116,12 +116,16 @@ const DART_RESERVED: &[&str] = &[ "while", "with", "yield", ]; -/// Words Dart takes as a member's name but not as a class's. +/// Dart's built-in identifiers (no type may take them), and the types the constants use or name, +/// which a class or constant of that name would shadow. const DART_BUILT_IN: &[&str] = &[ "abstract", "as", + "bool", + "Color", "covariant", "deferred", + "double", "dynamic", "export", "extension", @@ -131,15 +135,20 @@ const DART_BUILT_IN: &[&str] = &[ "get", "implements", "import", + "int", "interface", "late", "library", + "List", "mixin", + "num", + "Object", "operator", "part", "required", "set", "static", + "String", "typedef", ]; @@ -160,7 +169,7 @@ fn dart_ident(name: &str, pascal: bool) -> String { if out.is_empty() || out.starts_with(|c: char| c.is_ascii_digit()) { out.insert(0, if pascal { 'V' } else { 'v' }); } - if DART_RESERVED.contains(&out.as_str()) || (pascal && DART_BUILT_IN.contains(&out.as_str())) { + if DART_RESERVED.contains(&out.as_str()) || DART_BUILT_IN.contains(&out.as_str()) { out.push('_'); } out diff --git a/crates/engine/src/variables_io_tests.rs b/crates/engine/src/variables_io_tests.rs index 8cc6be80..482c220a 100644 --- a/crates/engine/src/variables_io_tests.rs +++ b/crates/engine/src/variables_io_tests.rs @@ -422,6 +422,28 @@ fn dart_export_names_are_valid_dart() { } } +#[test] +fn dart_export_names_never_shadow_dart_types() { + let mut s = Session::new(); + ex(&mut s, "variable.createCollection", json!({"name": "Color"})); + ex(&mut s, "variable.createCollection", json!({"name": "String"})); + for name in ["double", "int", "bool", "num"] { + ex(&mut s, "variable.create", json!({"collection": "Color", "name": name, "type": "number", "value": 1})); + } + let dart = ex(&mut s, "variable.export", json!({"format": "dart"}))["text"].as_str().unwrap().to_string(); + // A class `Color` would hide dart:ui's `Color`, a constant `double` the type of those after it. + for want in [ + "abstract final class Color_ {", + "abstract final class String_ {", + "static const double double_ = 1;", + "static const double int_ = 1;", + "static const double bool_ = 1;", + "static const double num_ = 1;", + ] { + assert!(dart.contains(want), "{want:?} in\n{dart}"); + } +} + #[test] fn paints_replaced_through_node_set_keep_unchanged_stop_bindings() { let mut s = Session::new();