Add support for creating ctx.attr/files/file

Bug: 528225104
Change-Id: I1840043a1a2c80ade2162e197537756e6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/24080
Reviewed-by: Cole Faust <colefaust@google.com>
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/starlark/Cargo.lock b/src/gn/starlark/Cargo.lock
index fe40557..8e1fb30 100644
--- a/src/gn/starlark/Cargo.lock
+++ b/src/gn/starlark/Cargo.lock
@@ -24,11 +24,12 @@
 [[package]]
 name = "allocative"
 version = "0.3.6"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "allocative_derive",
  "bumpalo",
  "ctor",
+ "dashmap",
  "hashbrown 0.16.1",
  "num-bigint",
 ]
@@ -36,11 +37,11 @@
 [[package]]
 name = "allocative_derive"
 version = "0.3.6"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -55,7 +56,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
 dependencies = [
- "unicode-width",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
@@ -92,9 +93,9 @@
 
 [[package]]
 name = "arrayvec"
-version = "0.7.7"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe"
+checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
 
 [[package]]
 name = "async-trait"
@@ -104,7 +105,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -170,9 +171,9 @@
 
 [[package]]
 name = "bitflags"
-version = "2.13.0"
+version = "2.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
+checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
 
 [[package]]
 name = "blake3"
@@ -206,22 +207,22 @@
 
 [[package]]
 name = "bytemuck"
-version = "1.25.0"
+version = "1.25.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
+checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424"
 dependencies = [
  "bytemuck_derive",
 ]
 
 [[package]]
 name = "bytemuck_derive"
-version = "1.10.2"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -232,9 +233,9 @@
 
 [[package]]
 name = "cc"
-version = "1.2.65"
+version = "1.2.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
+checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38"
 dependencies = [
  "find-msvc-tools",
  "shlex",
@@ -254,18 +255,18 @@
 
 [[package]]
 name = "clap"
-version = "4.6.1"
+version = "4.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+checksum = "dd059f9da4f5c36b3787f65d38ccaab1cc315f07b01f89abc8359ee6a8205011"
 dependencies = [
  "clap_builder",
 ]
 
 [[package]]
 name = "clap_builder"
-version = "4.6.0"
+version = "4.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
 dependencies = [
  "anstyle",
  "clap_lex",
@@ -290,7 +291,7 @@
 [[package]]
 name = "cmp_any"
 version = "0.8.1"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 
 [[package]]
 name = "cobs"
@@ -309,7 +310,7 @@
 dependencies = [
  "serde",
  "termcolor",
- "unicode-width",
+ "unicode-width 0.2.2",
 ]
 
 [[package]]
@@ -350,9 +351,9 @@
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
 dependencies = [
  "crossbeam-epoch",
  "crossbeam-utils",
@@ -360,18 +361,18 @@
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.18"
+version = "0.9.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
 dependencies = [
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.21"
+version = "0.8.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
 
 [[package]]
 name = "crypto-common"
@@ -385,9 +386,9 @@
 
 [[package]]
 name = "ctor"
-version = "1.0.7"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
+checksum = "a394189d59f9befacce833f337f7b1eca5e9a91221bcdd4d28e0114d96e597b3"
 dependencies = [
  "link-section",
  "linktime-proc-macro",
@@ -418,7 +419,7 @@
  "proc-macro2",
  "quote",
  "scratch",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -431,7 +432,7 @@
  "indexmap",
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -447,7 +448,7 @@
  "indexmap",
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -516,7 +517,7 @@
  "convert_case",
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
  "unicode-xid",
 ]
 
@@ -534,7 +535,7 @@
 [[package]]
 name = "display_container"
 version = "0.9.0"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "either",
  "indenter",
@@ -543,7 +544,7 @@
 [[package]]
 name = "dupe"
 version = "0.9.1"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "dupe_derive",
 ]
@@ -551,11 +552,11 @@
 [[package]]
 name = "dupe_derive"
 version = "0.9.1"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -663,7 +664,7 @@
 dependencies = [
  "cfg-if",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -859,9 +860,9 @@
 
 [[package]]
 name = "link-section"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24670b639492630905459a6c7d47f063d33c2d4fcd5362f6e5827c5613976c9f"
+checksum = "e333fe507b738576d6da5bb3f1a7d7a1c80307ed9ef31624c057d844c19c93e9"
 
 [[package]]
 name = "linktime-proc-macro"
@@ -935,7 +936,7 @@
  "quote",
  "regex-syntax",
  "rustc_version",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -968,18 +969,9 @@
 
 [[package]]
 name = "memchr"
-version = "2.8.2"
+version = "2.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
-
-[[package]]
-name = "memoffset"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-dependencies = [
- "autocfg",
-]
+checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
 
 [[package]]
 name = "nibble_vec"
@@ -996,7 +988,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
 dependencies = [
- "bitflags 2.13.0",
+ "bitflags 2.13.1",
  "cfg-if",
  "cfg_aliases",
  "libc",
@@ -1004,9 +996,9 @@
 
 [[package]]
 name = "num-bigint"
-version = "0.4.6"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
 dependencies = [
  "num-integer",
  "num-traits",
@@ -1040,7 +1032,7 @@
 [[package]]
 name = "pagable"
 version = "0.4.1"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "allocative",
  "anyhow",
@@ -1069,17 +1061,18 @@
  "static_interner",
  "strong_hash",
  "take_mut",
+ "thiserror",
  "triomphe",
 ]
 
 [[package]]
 name = "pagable_derive"
 version = "0.4.1"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -1185,9 +1178,9 @@
 
 [[package]]
 name = "rand"
-version = "0.10.1"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
 dependencies = [
  "getrandom",
  "rand_core",
@@ -1215,7 +1208,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
 dependencies = [
- "bitflags 2.13.0",
+ "bitflags 2.13.1",
 ]
 
 [[package]]
@@ -1235,14 +1228,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
 name = "regex"
-version = "1.12.4"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
+checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1252,9 +1245,9 @@
 
 [[package]]
 name = "regex-automata"
-version = "0.4.14"
+version = "0.4.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1282,7 +1275,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
 dependencies = [
- "bitflags 2.13.0",
+ "bitflags 2.13.1",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -1291,9 +1284,9 @@
 
 [[package]]
 name = "rustversion"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
 
 [[package]]
 name = "rustyline"
@@ -1301,7 +1294,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63"
 dependencies = [
- "bitflags 2.13.0",
+ "bitflags 2.13.1",
  "cfg-if",
  "clipboard-win",
  "fd-lock",
@@ -1312,7 +1305,7 @@
  "nix",
  "radix_trie",
  "unicode-segmentation",
- "unicode-width",
+ "unicode-width 0.1.14",
  "utf8parse",
  "windows-sys 0.52.0",
 ]
@@ -1410,7 +1403,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -1434,7 +1427,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -1461,9 +1454,9 @@
 
 [[package]]
 name = "spin"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
 dependencies = [
  "lock_api",
 ]
@@ -1477,7 +1470,7 @@
 [[package]]
 name = "starlark"
 version = "0.14.2"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "allocative",
  "anyhow",
@@ -1497,7 +1490,6 @@
  "inventory",
  "itertools",
  "maplit",
- "memoffset",
  "num-bigint",
  "num-traits",
  "once_cell",
@@ -1521,18 +1513,18 @@
 [[package]]
 name = "starlark_derive"
 version = "0.14.2"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "dupe",
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
 name = "starlark_map"
 version = "0.14.2"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "allocative",
  "dupe",
@@ -1547,7 +1539,7 @@
 [[package]]
 name = "starlark_syntax"
 version = "0.14.2"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "allocative",
  "annotate-snippets",
@@ -1585,7 +1577,7 @@
 [[package]]
 name = "strong_hash"
 version = "0.1.0"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "ref-cast",
  "strong_hash_derive",
@@ -1594,10 +1586,10 @@
 [[package]]
 name = "strong_hash_derive"
 version = "0.1.0"
-source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#4fdfa21b978a8fb1fd910b07f1d2b2be0ea89d7e"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#426a43164741eec393f074c1670c985491561ff7"
 dependencies = [
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
@@ -1625,9 +1617,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.118"
+version = "2.0.119"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1666,7 +1658,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 dependencies = [
- "unicode-width",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
@@ -1686,14 +1678,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.118",
+ "syn 2.0.119",
 ]
 
 [[package]]
 name = "triomphe"
-version = "0.1.15"
+version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39"
+checksum = "b40688ea6389c8171614b25491f71d4a27946e0c7ce2da1c6de27e25abf1a0ae"
 dependencies = [
  "serde",
  "stable_deref_trait",
@@ -1741,6 +1733,12 @@
 checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
+[[package]]
 name = "unicode-xid"
 version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1784,6 +1782,15 @@
 
 [[package]]
 name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
 version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
@@ -1857,6 +1864,6 @@
 
 [[package]]
 name = "zmij"
-version = "1.0.21"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
diff --git a/src/gn/starlark/crates/attr/src/ctx.rs b/src/gn/starlark/crates/attr/src/ctx.rs
new file mode 100644
index 0000000..21d11c1
--- /dev/null
+++ b/src/gn/starlark/crates/attr/src/ctx.rs
@@ -0,0 +1,248 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use starlark::{
+    collections::SmallMap,
+    values::{
+        record::{FieldGen, FrozenRecordType, Record},
+        typing::TypeInstanceId,
+        FrozenHeap, FrozenValue, FrozenValueTyped, Heap, Value,
+    },
+};
+use types::LabelRef;
+
+use crate::{
+    schema::{AllowFilesSchema, AttrKind, AttrSchema},
+    value::AttrValue,
+    Attr, Session,
+};
+
+/// Contains ctx.attr, ctx.files, and ctx.file.
+///
+/// See https://bazel.build/rules/lib/builtins/ctx for more info on what they are.
+pub struct CtxAttr<'v> {
+    pub attr: Value<'v>,
+    pub files: Value<'v>,
+    pub file: Value<'v>,
+}
+
+/// The rule attr schema.
+///
+/// This, roughly speaking, corresponds to the following starlark code:
+/// {
+///   "foo": attr.label_list(...),
+///   "bar": attr.string(...),
+/// }
+pub struct CtxAttrSchema {
+    attrs: SmallMap<String, AttrSchema>,
+    attr: FrozenValueTyped<'static, FrozenRecordType>,
+    files: FrozenValueTyped<'static, FrozenRecordType>,
+    file: FrozenValueTyped<'static, FrozenRecordType>,
+}
+
+impl CtxAttrSchema {
+    /// Creates a new `CtxAttrSchema`.
+    pub fn new(attrs: SmallMap<String, AttrSchema>, heap: &FrozenHeap) -> Self {
+        let mut attrs_fields = SmallMap::with_capacity(attrs.len());
+        let mut file_fields = SmallMap::new();
+        let mut files_fields = SmallMap::new();
+
+        let any = || -> FieldGen<FrozenValue> {
+            FieldGen::new(starlark::values::typing::TypeCompiled::any(), None)
+        };
+
+        for (name, attr) in &attrs {
+            attrs_fields.insert(name.clone(), any());
+
+            if matches!(attr.kind, AttrKind::Label | AttrKind::LabelList) {
+                files_fields.insert(name.clone(), any());
+            }
+            if matches!(attr.allow_files, AllowFilesSchema::Single(_)) {
+                file_fields.insert(name.clone(), any());
+            }
+        }
+
+        CtxAttrSchema {
+            attrs,
+            attr: FrozenValueTyped::new(heap.alloc(FrozenRecordType::new(
+                "rule_attr",
+                attrs_fields,
+                TypeInstanceId::r#gen(),
+            )))
+            .unwrap(),
+            files: FrozenValueTyped::new(heap.alloc(FrozenRecordType::new(
+                "rule_files",
+                files_fields,
+                TypeInstanceId::r#gen(),
+            )))
+            .unwrap(),
+            file: FrozenValueTyped::new(heap.alloc(FrozenRecordType::new(
+                "rule_file",
+                file_fields,
+                TypeInstanceId::r#gen(),
+            )))
+            .unwrap(),
+        }
+    }
+
+    /// Constructs the record values for `ctx.attr`, `ctx.file`, and `ctx.files`
+    /// from the resolved attribute values.
+    pub fn create_ctx_fields<'v, S: Session>(
+        &self,
+        fields: &[Attr],
+        session: &S,
+        current_toolchain: &LabelRef,
+        heap: &Heap<'v>,
+    ) -> starlark::Result<CtxAttr<'v>> {
+        let mut ctx_attr = Vec::with_capacity(self.attr.len());
+        let mut ctx_files = Vec::with_capacity(self.files.len());
+        let mut ctx_file = Vec::with_capacity(self.file.len());
+
+        debug_assert!(fields.len() == self.attrs.len());
+        for ((name, schema), attr) in self.attrs.iter().zip(fields.iter()) {
+            let AttrValue { attr, file, files } = attr
+                .to_value(schema, session, current_toolchain, heap)
+                .map_err(|e| e.with_context(format!("for attribute `{name}`")))?;
+
+            ctx_attr.push(attr);
+
+            if let Some(files) = files {
+                ctx_files.push(files);
+            }
+
+            if let Some(file) = file {
+                ctx_file.push(file);
+            }
+        }
+
+        debug_assert!(ctx_file.len() == self.file.len());
+        debug_assert!(ctx_files.len() == self.files.len());
+
+        Ok(CtxAttr {
+            attr: heap.alloc(Record::new(
+                self.attr.to_value_typed(),
+                ctx_attr.into_boxed_slice(),
+            )),
+            files: heap.alloc(Record::new(
+                self.files.to_value_typed(),
+                ctx_files.into_boxed_slice(),
+            )),
+            file: heap.alloc(Record::new(
+                self.file.to_value_typed(),
+                ctx_file.into_boxed_slice(),
+            )),
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use starlark::{environment::GlobalsBuilder, eval::Evaluator, values::list::UnpackList};
+    use starlark_derive::starlark_module;
+    use testutils::{FakeEvalContext, FakeTarget, FakeTargetRef};
+    use types::{EvaluatorContextExt as _, File, Label, PackageRef};
+
+    use super::*;
+    use crate::globals::{AttrModule, AttrSpecArgs};
+
+    fn make_attr_schema<'v>(
+        kind: crate::AttrKind,
+        args: AttrSpecArgs<'v>,
+        eval: &mut Evaluator<'v, '_, '_>,
+    ) -> starlark::Result<starlark::values::Value<'v>> {
+        crate::schema::AttrSchema::create(
+            kind,
+            args,
+            types::PackageRef::root(),
+            &types::PathResolver::new_for_testing(),
+            &eval.heap(),
+        )
+    }
+
+    #[starlark_module]
+    fn register_ctx_test_globals(builder: &mut GlobalsBuilder) {
+        fn to_attrs<'v>(
+            schema: SmallMap<String, &'v AttrSchema>,
+            values: UnpackList<Value<'v>>,
+            eval: &mut Evaluator<'v, '_, '_>,
+        ) -> starlark::Result<Value<'v>> {
+            let context: &FakeEvalContext = eval.context();
+            let fields: Vec<Attr> = schema
+                .values()
+                .zip(values.items)
+                .map(|(attr_schema, val)| {
+                    Attr::create(
+                        attr_schema,
+                        Some(val),
+                        &context.package.as_ref(),
+                        &context.path_resolver,
+                    )
+                })
+                .collect::<Result<_, _>>()?;
+
+            let ctx = CtxAttrSchema::new(
+                schema.into_iter().map(|(k, v)| (k, (*v).clone())).collect(),
+                eval.frozen_heap(),
+            )
+            .create_ctx_fields(
+                &fields,
+                &context.session,
+                &context.current_toolchain.as_ref(),
+                &eval.heap(),
+            )?;
+
+            Ok(eval.heap().alloc((ctx.attr, ctx.files, ctx.file)))
+        }
+    }
+
+    #[test]
+    fn test_create_ctx_fields() {
+        let mut a = testutils::Assert::default();
+
+        let target_label = Label::new(PackageRef::root().to_owned(), "bar".to_owned());
+        let file1 = File::intern("out.cc");
+        let target_bar = FakeTargetRef::new(FakeTarget {
+            outputs: vec![file1.clone()],
+            ..Default::default()
+        });
+        a.context().session.insert_target(target_label, target_bar);
+
+        a.modify_globals(|builder| {
+            builder.set("attr", AttrModule { make_attr_schema });
+            register_ctx_test_globals(builder);
+        });
+
+        a.pass(
+            r#"
+attrs, files, file = to_attrs(
+    schema = {
+        "srcs": attr.label_list(),
+        "hdr": attr.label(allow_single_file = True),
+        "bool_attr": attr.bool(),
+    },
+    values = [
+        [":bar"],
+        ":bar",
+        True,
+    ],
+)
+
+def assert_eq(a, b):
+    if a != b:
+        fail("expected %s, got %s" % (b, a))
+
+assert_eq(attrs.bool_attr, True)
+assert_eq(files.srcs, [make_file("out.cc")])
+assert_eq(files.hdr, [make_file("out.cc")])
+assert_eq(file.hdr, make_file("out.cc"))
+
+if hasattr(files, "bool_attr"):
+    fail("files should not have bool_attr")
+
+if hasattr(file, "bool_attr"):
+    fail("file should not have bool_attr")
+"#,
+        );
+    }
+}
diff --git a/src/gn/starlark/crates/attr/src/lib.rs b/src/gn/starlark/crates/attr/src/lib.rs
index 93bb68a..5eb676c 100644
--- a/src/gn/starlark/crates/attr/src/lib.rs
+++ b/src/gn/starlark/crates/attr/src/lib.rs
@@ -5,6 +5,7 @@
 pub mod allow_files;
 pub mod attr;
 pub mod cfg;
+pub mod ctx;
 pub mod errors;
 pub mod globals;
 pub mod schema;
@@ -14,6 +15,7 @@
 pub use allow_files::AllowFiles;
 pub use attr::{Attr, LabelOrFile};
 pub use cfg::AttrCfg;
+pub use ctx::{CtxAttr, CtxAttrSchema};
 pub use errors::Error;
 pub use globals::{AttrModule, AttrSpecArgs};
 pub use schema::{AllowFilesSchema, AttrKind, AttrSchema};