Gate runtime binding array on an enable.

The runtime `binding_array` feature will only be available on certain
platforms so it should be gated behind an enable. Add `enable
chromium_experimental_dynamic_binding` as a temporary feature flag.

Bug: 439626909
Change-Id: I98fcec47cb7cf8432a300dd5692251d400535f9b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/258556
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/docs/tint/extensions/chromium_experimental_dynamic_binding.md b/docs/tint/extensions/chromium_experimental_dynamic_binding.md
new file mode 100644
index 0000000..f10d134
--- /dev/null
+++ b/docs/tint/extensions/chromium_experimental_dynamic_binding.md
@@ -0,0 +1,122 @@
+# Chromium Experimental Dynamic Binding
+
+The `chromium_experimental_dynamic_binding` is an experimental extension that allows using both
+runtime sized `binding_array` and type-less `binding_array`. This provides the needed basis for
+dynamic binding (a.k.a. bind-less).
+
+# Status
+
+This extension is experimental and the syntax is being discussed. No official WebGPU specification
+has been written yet.
+
+# Availability
+
+| Platform | Notes |
+| SPIR-V | Requires `SPV_EXT_descriptor_indexing` extension and `RuntimeDescriptorArray` capability |
+| HLSL | Supported for DXC, not FXC |
+| MSL | Supported (TODO determine if there are Metal version restrictions) |
+| GLSL | Not supported |
+
+Due to limited availability, this will need an `enable` statement to be used. For this experimental
+extension it would be `enable chromium_experimental_dynamic_binding`.
+
+# Specification
+
+This extension adds new features to the `binding_array` feature added previously with the
+`sized_binding_arrays` extension [1].
+
+## `binding_array<T>`
+
+* A new `binding_array<T>` type is added.
+* `T` is a format-less storage texture (e.g. `texture_storage_2d<f32>`), sampled texture, multisampled
+  texture, or depth texture.
+* This is a runtime-array version of the `binding_array<T, N>` as added by `sized_binding_arrays`.
+* A runtime binding array may not be passed as a function parameter. This is because there is no way
+  in WGSL to currently write the needed pointer type (e.g.
+  `ptr<handle, binding_array<texture_1d<f32>>, write>`).
+* An out-of-bounds read from the `binding_array<T>` will return any value from the `binding_array`.
+
+
+### `arrayLength`
+```
+@must_use fn arrayLength(a: ptr<handle, binding_array<T>, RW>) -> u32
+```
+
+Similar to the runtime-array version, returns the length of the array.
+
+## `binding_array`
+
+* A new `binding_array` type is added
+* This is a type-less version of `binding_array<T>`. As such, any restrictions on runtime binding
+  array is relevant to `binding_array`.
+* A `binding_array` can not be accessed with the usual array subscript operators. e.g. the following
+  is disallowed:
+
+  ```
+  var a: binding_array;
+  fn foo() {
+      var b = a[0];
+  }
+  ```
+* Two helper methods `getBinding` and `hasBinding` are provided for accessing a `binding_array`.
+
+### `hasBinding`
+```
+@must_use fn hasBinding<T>(a: binding_array, index: I) -> bool
+```
+* `I` is an `i32` or `u32`
+* `T` is a format-less storage texture (e.g. `texture_storage_2d<f32>`), sampled texture, multisampled
+  texture, or depth texture.
+
+`hasBinding` returns true if the item a `index` of the array is of type `T`.
+
+### `getBinding`
+```
+@must_use fn getBinding<T>(a: binding_array, index: I) -> T
+```
+* `I` is an `i32` or `u32`
+* `T` is a format-less storage texture (e.g. `texture_storage_2d<f32>`), sampled texture, multisampled
+  texture, or depth texture.
+
+`getBinding` returns the value at `index` of type `T`.
+
+If `index` is outside the bounds of the binding array then a default texture of type `T` will be
+returned. If the item at `index` is not of type `T` then a default texture of type `T` is returned.
+
+### `arrayLength`
+```
+@must_use fn arrayLength(a: ptr<handle, binding_array, RW>) -> u32
+```
+
+Similar to the runtime-array version, returns the length of the array.
+
+# Example usage
+
+## `binding_array<T>`
+
+```
+enable chromium_experimental_dynamic_binding;
+
+@group(0) @binding(0) var sampled_textures : binding_array<texture_2d<f32>>;
+
+@fragment fn fs() {
+    let texture_load = textureLoad(sampled_textures[0], vec2(0, 0), 0);
+}
+```
+
+## `binding_array`
+
+```
+enable chromium_experimental_dynamic_binding;
+
+@group(0) @binding(0) var textures : binding_array;
+
+@fragment fn fs() {
+    if (hasBinding<texture_2d<f32>>(textures, 0)) {
+        let tex = textureLoad(getBinding<texture_2d<f32>>(textures, 0));
+    }
+}
+```
+
+# References
+1.[Sized Binding Arrays](https://github.com/gpuweb/gpuweb/blob/main/proposals/sized-binding-arrays.md)
diff --git a/src/tint/cmd/bench/enums_wgsl_bench.cc b/src/tint/cmd/bench/enums_wgsl_bench.cc
index b58f451..8d3cd3f 100644
--- a/src/tint/cmd/bench/enums_wgsl_bench.cc
+++ b/src/tint/cmd/bench/enums_wgsl_bench.cc
@@ -117,83 +117,90 @@
         "chromium_experimencal_barycentric_coord",
         "chromium_experimental_Oarycentric_coord",
         "chrttmium_experimental_bv__rycentric_KKoord",
-        "chromium_epxxrimenta8_framebuffer_fe5ch",
-        "chromim_experimental_frame__uffer_qqtcF",
-        "chromium_exerimental_fqqamebuffer_fetch",
+        "chrxxmium_8perimental_dynamic_5inding",
+        "__hromFumexperimental_ynqqmic_binding",
+        "chromium_xperimentqql_dynamic_binding",
+        "chromium_experimental_dynamic_binding",
+        "chromum_experim33ntal_dynam66c_biOding",
+        "chromium_QQxperimental_6y9amic_ttoonding",
+        "chromium_experimenta_dynamic_bin66ing",
+        "hromxum_experimental_zzr66mebufferOfetch",
+        "chromium_experimental_framebyyffer_fetch",
+        "chrmium_experimental_fraeHHuffer_feZch",
         "chromium_experimental_framebuffer_fetch",
-        "h66omiu33_experimenOal_framebuffer_fetch",
-        "ch6ottiumooexperQQmental_frameb9ffer_fetch",
-        "chomium_experimen66al_framebuffer_fetch",
-        "chrom66um_Oxperiental_xzzmediate",
-        "chroyyium_experimental_immediate",
-        "Zhromium_exerimntal_iHHZediate",
+        "chromium_expeimeWWtal_framebuq4fer_fetch",
+        "chromium_experimental_fOOamebuffer_etch",
+        "chroomium_experimntalhframebuffr_fetcY",
+        "chomium_experiental_immedite",
+        "chromium_experimetal_immFdiate",
+        "chromium_expermental_imwediate",
         "chromium_experimental_immediate",
-        "chromium_expeqimet44l_immediWWte",
-        "chromium_experimntal_immeOOiate",
-        "hromium_experimetal_iYhedooate",
-        "chomium_experiental_pixel_loca",
-        "chromum_experimental_pixel_lFcal",
-        "chromium_expewimentalpixel_local",
+        "chromiumfexperimental_immedGte",
+        "chrKKmium_eqperimental_immediate",
+        "chromi3m_exmmeriFental_immediate",
+        "chromium_experimentalpixel_local",
+        "chromium_experiental_pixel_locaq",
+        "chromium_experimbbntb_pixel_local",
         "chromium_experimental_pixel_local",
-        "chromffum_expeKmentG_pixel_local",
-        "chromiuq_KKxperimental_pixel_local",
-        "chromium_eFpe3imental_mmixel_local",
-        "chromium_experimental_subgroup_mtrix",
-        "chromium_experimental_subgoqp_matrix",
-        "chromium_ebperimental_subgroub_matrix",
+        "ihromium_experimental_pixel_loca",
+        "chromium_experimentaqpOOxel_local",
+        "chroTTium_exvverimental_pixel_local",
+        "chromium_experimental_subgrouFF_matrix",
+        "chromifm_experimenta00PsubgroQp_mtrix",
+        "chromium_experPmental_subgroup_matrix",
         "chromium_experimental_subgroup_matrix",
-        "ciiomim_experimental_subgroup_matrix",
-        "chromOOum_experimeqtal_subgroup_matix",
-        "chrovvium_experimentalTTsubgroup_matrix",
-        "chromium_internal_grapFFite",
-        "chromPumQintenal_g00aphfte",
-        "chromium_iPternal_graphite",
+        "cssomium_experimental_subgroup_mat77ix",
+        "chromium_exbberimenCal_subgroup_mRRtrix",
+        "chromium_experimental_subgroup_mXXtrix",
+        "chromium_inqerOCCal_OOaphite",
+        "chrmium_Lntesnal_guaphite",
+        "chromium_internal_gXaphite",
         "chromium_internal_graphite",
-        "hromium_interna77s_graphite",
-        "chromium_iRRtCrnal_graphbbte",
-        "chromium_internal_graphXXte",
-        "chOOomOCCum_interna_iqput_attachments",
-        "chosium_iuternal_input_attachmentL",
-        "chromium_internXl_input_attachments",
+        "cromium_internal_graphite",
+        "chromiOm_inerqqal_gahite",
+        "chr22mium_internal_graphite",
+        "chzzomium0inteXXny_input_attachments",
+        "chromium_internalVVinpP_aitachments",
+        "chnnomium_internalCinput_attachmnts",
         "chromium_internal_input_attachments",
-        "chromium_internal_input_attachmets",
-        "chomium_interna_input_tOachmenqqs",
-        "chromium_internal_i22put_attachments",
-        "clip_is0yzzceXX",
-        "clip_ditaVPies",
-        "clp_distnnnCes",
+        "chrHHmim_inqqernalinput_attachmentAA",
+        "chromium_internal_input_attchments",
+        "chromiuf_internal_input_KKachments",
+        "clipditaPcggs",
+        "clip_istances",
+        "4lip_disTTaNcec",
         "clip_distances",
-        "clip_disqanceHA",
-        "clip_dstances",
-        "flidistKKnces",
-        "dul_sourceggbPnding",
-        "dua_source_blending",
-        "duNl_sourcec4lenTTing",
+        "cli_distpp7lces",
+        "cgzip_dstancNs",
+        "uulip_bitanXXes",
+        "dual_soure_blending",
+        "dualsoQrce_bled88nK",
+        "dual_souce_blend9qg",
         "dual_source_blending",
-        "dual_sppurce_blendin7",
-        "dul_zzgurce_NNlendig",
-        "bXXual_suuurce_bnding",
-        "f6",
-        "88",
-        "9q",
+        "dual_source_bl11nding",
+        "Fuaii_source_bl22ding",
+        "dual_soure_b77ending",
+        "NN6",
+        "VV16",
+        "Fw11W",
         "f16",
-        "f116",
-        "f122",
-        "776",
-        "primitNN2e_indx",
-        "primitVVve_index",
-        "FrimiWWive_inw11x",
+        "ww6",
+        "fD6",
+        "fK",
+        "primif11ve_inPPeh",
+        "prmitive_index",
+        "primitive_indeYY",
         "primitive_index",
-        "primitvewwindex",
-        "pDimitive_index",
-        "primitiv_indeK",
-        "sub11PPfrph",
-        "subgroup",
-        "suYYgroups",
+        "pHHimittveikkdex",
+        "rrrimitive_index",
+        "pWWimitive_ndssx",
+        "suYroups",
+        "sbgroqpL",
+        "sfbv22rouus",
         "subgroups",
-        "subHtkkops",
-        "rrubgroups",
-        "subgWWosss",
+        "subgous",
+        "suYgrous",
+        "subyr77upEY",
     };
     for (auto _ : state) {
         for (auto* str : kStrings) {
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt b/src/tint/cmd/fuzz/wgsl/dictionary.txt
index 08b5d8d..7e896d3 100644
--- a/src/tint/cmd/fuzz/wgsl/dictionary.txt
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt
@@ -162,6 +162,7 @@
 "centroid"
 "chromium_disable_uniformity_analysis"
 "chromium_experimental_barycentric_coord"
+"chromium_experimental_dynamic_binding"
 "chromium_experimental_framebuffer_fetch"
 "chromium_experimental_immediate"
 "chromium_experimental_pixel_local"
diff --git a/src/tint/lang/wgsl/enums.cc b/src/tint/lang/wgsl/enums.cc
index 37a5cbb..1720c84 100644
--- a/src/tint/lang/wgsl/enums.cc
+++ b/src/tint/lang/wgsl/enums.cc
@@ -52,6 +52,9 @@
     if (str == "chromium_experimental_barycentric_coord") {
         return Extension::kChromiumExperimentalBarycentricCoord;
     }
+    if (str == "chromium_experimental_dynamic_binding") {
+        return Extension::kChromiumExperimentalDynamicBinding;
+    }
     if (str == "chromium_experimental_framebuffer_fetch") {
         return Extension::kChromiumExperimentalFramebufferFetch;
     }
@@ -95,6 +98,8 @@
             return "chromium_disable_uniformity_analysis";
         case Extension::kChromiumExperimentalBarycentricCoord:
             return "chromium_experimental_barycentric_coord";
+        case Extension::kChromiumExperimentalDynamicBinding:
+            return "chromium_experimental_dynamic_binding";
         case Extension::kChromiumExperimentalFramebufferFetch:
             return "chromium_experimental_framebuffer_fetch";
         case Extension::kChromiumExperimentalImmediate:
diff --git a/src/tint/lang/wgsl/enums.h b/src/tint/lang/wgsl/enums.h
index 5195320..660c1e7 100644
--- a/src/tint/lang/wgsl/enums.h
+++ b/src/tint/lang/wgsl/enums.h
@@ -115,6 +115,7 @@
     kUndefined,
     kChromiumDisableUniformityAnalysis,
     kChromiumExperimentalBarycentricCoord,
+    kChromiumExperimentalDynamicBinding,
     kChromiumExperimentalFramebufferFetch,
     kChromiumExperimentalImmediate,
     kChromiumExperimentalPixelLocal,
@@ -149,6 +150,7 @@
 constexpr std::string_view kExtensionStrings[] = {
     "chromium_disable_uniformity_analysis",
     "chromium_experimental_barycentric_coord",
+    "chromium_experimental_dynamic_binding",
     "chromium_experimental_framebuffer_fetch",
     "chromium_experimental_immediate",
     "chromium_experimental_pixel_local",
@@ -166,6 +168,7 @@
 static constexpr Extension kAllExtensions[] = {
     Extension::kChromiumDisableUniformityAnalysis,
     Extension::kChromiumExperimentalBarycentricCoord,
+    Extension::kChromiumExperimentalDynamicBinding,
     Extension::kChromiumExperimentalFramebufferFetch,
     Extension::kChromiumExperimentalImmediate,
     Extension::kChromiumExperimentalPixelLocal,
diff --git a/src/tint/lang/wgsl/enums_test.cc b/src/tint/lang/wgsl/enums_test.cc
index 7ce886b..a42de4c 100644
--- a/src/tint/lang/wgsl/enums_test.cc
+++ b/src/tint/lang/wgsl/enums_test.cc
@@ -228,6 +228,7 @@
 static constexpr ExtensionCase kValidExtensionCases[] = {
     {"chromium_disable_uniformity_analysis", Extension::kChromiumDisableUniformityAnalysis},
     {"chromium_experimental_barycentric_coord", Extension::kChromiumExperimentalBarycentricCoord},
+    {"chromium_experimental_dynamic_binding", Extension::kChromiumExperimentalDynamicBinding},
     {"chromium_experimental_framebuffer_fetch", Extension::kChromiumExperimentalFramebufferFetch},
     {"chromium_experimental_immediate", Extension::kChromiumExperimentalImmediate},
     {"chromium_experimental_pixel_local", Extension::kChromiumExperimentalPixelLocal},
@@ -248,39 +249,42 @@
     {"chomium_experiooetal_barcentric_coord", Extension::kUndefined},
     {"chromium_experimentl_barycentzzc_coord", Extension::kUndefined},
     {"chromium_expperimental1barycentric_coori", Extension::kUndefined},
-    {"chXXomium_experimental_framebuffer_fetch", Extension::kUndefined},
-    {"chr99mi55m_experiIIennnal_framebuffer_fetch", Extension::kUndefined},
-    {"chromiumSSerrperimenaaal_fraHHebuffer_fetYh", Extension::kUndefined},
-    {"chkkomium_eperimntal_immediat", Extension::kUndefined},
-    {"jhromium_experRmental_immeigte", Extension::kUndefined},
-    {"chromiubexperiental_immediate", Extension::kUndefined},
-    {"chromium_experimentjl_pixel_local", Extension::kUndefined},
-    {"chroium_experimental_pixel_local", Extension::kUndefined},
-    {"cromium_qxperimental_pixl_local", Extension::kUndefined},
-    {"chromium_experimental_sNbgroup_matrix", Extension::kUndefined},
-    {"chromium_exprimenta_suvvgroup_matrix", Extension::kUndefined},
-    {"chromium_experimentaQQ_sbgroup_matrix", Extension::kUndefined},
-    {"chroium_ffnternal_grahire", Extension::kUndefined},
-    {"chromium_internal_grjphite", Extension::kUndefined},
-    {"chromum_inwwerna2_grapNNite", Extension::kUndefined},
-    {"chromium_internalinput_attachments", Extension::kUndefined},
-    {"crrromium_internal_input_attachments", Extension::kUndefined},
-    {"Ghromium_internal_input_attachments", Extension::kUndefined},
-    {"clip_distanceFF", Extension::kUndefined},
-    {"cEipdtances", Extension::kUndefined},
-    {"cli_rristances", Extension::kUndefined},
-    {"dual_suce_blending", Extension::kUndefined},
-    {"dul_DoXrcJJ_blending", Extension::kUndefined},
-    {"dul_source_lening", Extension::kUndefined},
-    {"k", Extension::kUndefined},
-    {"16", Extension::kUndefined},
-    {"J1", Extension::kUndefined},
-    {"primitive_incex", Extension::kUndefined},
-    {"pOimitive_index", Extension::kUndefined},
-    {"__rimiKKitte_indevv", Extension::kUndefined},
-    {"xubgro5p8", Extension::kUndefined},
-    {"suFq__ups", Extension::kUndefined},
-    {"sqqgroups", Extension::kUndefined},
+    {"chromium_experimental_dyXXamic_binding", Extension::kUndefined},
+    {"chromi55m_eIIperimental_dynnami99_binding", Extension::kUndefined},
+    {"chroSSium_experiaaYntal_dynamic_binrrHHng", Extension::kUndefined},
+    {"chromum_xperimentalframebuffHrkkfetch", Extension::kUndefined},
+    {"chrojium_xRReimental_frgmebuffer_fetch", Extension::kUndefined},
+    {"hromium_experimental_ramebbffer_fetch", Extension::kUndefined},
+    {"chromium_experimental_ijmediate", Extension::kUndefined},
+    {"chromium_experimental_imediate", Extension::kUndefined},
+    {"cromum_experimentalqimmediate", Extension::kUndefined},
+    {"chromium_experimNNntal_pixel_loca", Extension::kUndefined},
+    {"chromium_expermentalpivvel_local", Extension::kUndefined},
+    {"chromium_experiQQental_pixl_local", Extension::kUndefined},
+    {"hromium_exprimertal_subgroup_ffatrix", Extension::kUndefined},
+    {"chromium_ejperimental_subgroup_matrix", Extension::kUndefined},
+    {"chromium_expewim8n2al_subgroupNNmatrix", Extension::kUndefined},
+    {"chromium_internl_graphite", Extension::kUndefined},
+    {"chromium_irrternal_graphite", Extension::kUndefined},
+    {"cGromium_internal_graphite", Extension::kUndefined},
+    {"chromium_internal_input_attFFchments", Extension::kUndefined},
+    {"chromium_iEteral_input_attahment", Extension::kUndefined},
+    {"chrmium_internal_inprrt_attachments", Extension::kUndefined},
+    {"lip_distanes", Extension::kUndefined},
+    {"DXp_diJJtances", Extension::kUndefined},
+    {"cl8pdistane", Extension::kUndefined},
+    {"dul_okrc_blen11ing", Extension::kUndefined},
+    {"dua_source_blending", Extension::kUndefined},
+    {"duJl_source_blendig", Extension::kUndefined},
+    {"c16", Extension::kUndefined},
+    {"fO6", Extension::kUndefined},
+    {"_KKttvv", Extension::kUndefined},
+    {"pr8mitive_nxxex", Extension::kUndefined},
+    {"primitveFqqd__x", Extension::kUndefined},
+    {"priitive_indeqq", Extension::kUndefined},
+    {"subgr6u33O", Extension::kUndefined},
+    {"s96grQttupoo", Extension::kUndefined},
+    {"sugro66ps", Extension::kUndefined},
 };
 
 using ExtensionParseTest = testing::TestWithParam<ExtensionCase>;
@@ -341,42 +345,42 @@
 };
 
 static constexpr LanguageFeatureCase kInvalidLanguageFeatureCases[] = {
-    {"ch336miumOprint", LanguageFeature::kUndefined},
-    {"chrom9oomttQQr6nt", LanguageFeature::kUndefined},
-    {"chom66um_print", LanguageFeature::kUndefined},
-    {"chroOium_testingexperimxnzza66", LanguageFeature::kUndefined},
-    {"chromium_testyyng_experimental", LanguageFeature::kUndefined},
-    {"chromHHm_tesing_expZrimental", LanguageFeature::kUndefined},
-    {"cWWromium_testqg_shippe44", LanguageFeature::kUndefined},
-    {"chOOomium_testng_shipped", LanguageFeature::kUndefined},
-    {"hhromiYm_testng_shipped", LanguageFeature::kUndefined},
-    {"chomium_testing_shipped_with_kilwitch", LanguageFeature::kUndefined},
-    {"chomium_testing_shiFped_with_killswitch", LanguageFeature::kUndefined},
-    {"chromium_testing_shippe_wiwh_killswitch", LanguageFeature::kUndefined},
-    {"chomium_esting_unimpGffmented", LanguageFeature::kUndefined},
-    {"chqomium_testinKK_unimplemented", LanguageFeature::kUndefined},
-    {"cFromiumm_testing_unimplemented", LanguageFeature::kUndefined},
-    {"chromium_testing_unsafe_xperimental", LanguageFeature::kUndefined},
-    {"chromium_testing_unsae_experqmental", LanguageFeature::kUndefined},
-    {"chromium_tbbsing_unsafe_experimental", LanguageFeature::kUndefined},
-    {"packeii4x8_integer_dot_prduct", LanguageFeature::kUndefined},
-    {"packed_4OO8_inqegr_dot_product", LanguageFeature::kUndefined},
-    {"packed_4x8_intvvger_dot_produTTt", LanguageFeature::kUndefined},
-    {"pointer_compositFF_access", LanguageFeature::kUndefined},
-    {"pfintPrc00mposite_acQess", LanguageFeature::kUndefined},
-    {"pointer_composPte_access", LanguageFeature::kUndefined},
-    {"re77donl_and_readwrite_storagss_textures", LanguageFeature::kUndefined},
-    {"reabbonly_aCRd_readwrite_storage_textures", LanguageFeature::kUndefined},
-    {"readonly_and_readwrite_XXtorage_textures", LanguageFeature::kUndefined},
-    {"qiCCedbinding_OOOrray", LanguageFeature::kUndefined},
-    {"sizud_binding_asay", LanguageFeature::kUndefined},
-    {"sizeX_binding_array", LanguageFeature::kUndefined},
-    {"txel_buffers", LanguageFeature::kUndefined},
-    {"exel_bufqqe", LanguageFeature::kUndefined},
-    {"tex22l_buffers", LanguageFeature::kUndefined},
-    {"uyrestriXXte0_pointerparazzeters", LanguageFeature::kUndefined},
-    {"unresticted_pointer_pVVramiterP", LanguageFeature::kUndefined},
-    {"unrestricted_pointeCpnnrameters", LanguageFeature::kUndefined},
+    {"66roOium_przznt", LanguageFeature::kUndefined},
+    {"chromium_pryynt", LanguageFeature::kUndefined},
+    {"chroHHiuZpriZ", LanguageFeature::kUndefined},
+    {"chromium_qeWWting_exper44metal", LanguageFeature::kUndefined},
+    {"chromium_teting_eOOperimental", LanguageFeature::kUndefined},
+    {"oohhoYum_testing_experimenal", LanguageFeature::kUndefined},
+    {"chomium_testin_shippe", LanguageFeature::kUndefined},
+    {"chomium_testing_shiFped", LanguageFeature::kUndefined},
+    {"chromium_testinwshipped", LanguageFeature::kUndefined},
+    {"chromiumtesting_shippff_with_kiGKswitch", LanguageFeature::kUndefined},
+    {"chromium_testing_shippeq_with_killsKKitch", LanguageFeature::kUndefined},
+    {"cFromium_testing_shipped_wimmh_killswi3ch", LanguageFeature::kUndefined},
+    {"chromium_testing_uimplemented", LanguageFeature::kUndefined},
+    {"chromium_teqtin_unimplemented", LanguageFeature::kUndefined},
+    {"chrobibm_testing_unimplemented", LanguageFeature::kUndefined},
+    {"chromium_tesiing_unsafe_experimentl", LanguageFeature::kUndefined},
+    {"chromium_testing_unafe_exOOerimentaq", LanguageFeature::kUndefined},
+    {"chromium_testing_unsafTTvvexperimental", LanguageFeature::kUndefined},
+    {"packed_4x8_integer_dotFFproduct", LanguageFeature::kUndefined},
+    {"packfd_4x8_ineQerP00ot_product", LanguageFeature::kUndefined},
+    {"packed_4x8_intPger_dot_product", LanguageFeature::kUndefined},
+    {"pointer_compossste_accs77", LanguageFeature::kUndefined},
+    {"Cointer_compobbite_acceRRs", LanguageFeature::kUndefined},
+    {"pointer_composite_accesXX", LanguageFeature::kUndefined},
+    {"qOCCadoly_and_OOeadwrite_storage_textures", LanguageFeature::kUndefined},
+    {"rsadonly_and_reawrite_storageutextLres", LanguageFeature::kUndefined},
+    {"readonly_and_readwrite_storage_tXxtures", LanguageFeature::kUndefined},
+    {"sized_binding_arra", LanguageFeature::kUndefined},
+    {"izeqq_bidOng_arra", LanguageFeature::kUndefined},
+    {"sized_bind22ng_array", LanguageFeature::kUndefined},
+    {"tezyel_bXXffer", LanguageFeature::kUndefined},
+    {"exelPbufVVers", LanguageFeature::kUndefined},
+    {"texel_Cufernn", LanguageFeature::kUndefined},
+    {"nrestrqqcHHed_oinAAer_parameters", LanguageFeature::kUndefined},
+    {"unrestricted_pointer_parametrs", LanguageFeature::kUndefined},
+    {"unfestricKKed_pointer_parameer", LanguageFeature::kUndefined},
 };
 
 using LanguageFeatureParseTest = testing::TestWithParam<LanguageFeatureCase>;
diff --git a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
index f8e2b5b..efa7d89 100644
--- a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
@@ -203,7 +203,7 @@
     // Error when unknown extension found
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_barycentric_coord', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_immediate', 'chromium_experimental_pixel_local', 'chromium_experimental_subgroup_matrix', 'chromium_internal_graphite', 'chromium_internal_input_attachments', 'clip_distances', 'dual_source_blending', 'f16', 'primitive_index', 'subgroups')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_barycentric_coord', 'chromium_experimental_dynamic_binding', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_immediate', 'chromium_experimental_pixel_local', 'chromium_experimental_subgroup_matrix', 'chromium_internal_graphite', 'chromium_internal_input_attachments', 'clip_distances', 'dual_source_blending', 'f16', 'primitive_index', 'subgroups')");
     auto program = p->program();
     auto& ast = program.AST();
     EXPECT_EQ(ast.Enables().Length(), 0u);
diff --git a/src/tint/lang/wgsl/resolver/binding_array_test.cc b/src/tint/lang/wgsl/resolver/binding_array_test.cc
index 252f6a1..9744761 100644
--- a/src/tint/lang/wgsl/resolver/binding_array_test.cc
+++ b/src/tint/lang/wgsl/resolver/binding_array_test.cc
@@ -210,13 +210,6 @@
     EXPECT_EQ(r()->error(), R"(error: cannot use value of type 'u32' as type)");
 }
 
-TEST_F(ResolverBindingArrayTest, RuntimeBindingArray) {
-    GlobalVar("a", Binding(0_a), Group(0_a),
-              ty("binding_array", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32())));
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
 TEST_F(ResolverBindingArrayTest, InvalidCountZero) {
     GlobalVar(
         "a", Binding(0_a), Group(0_a),
@@ -315,6 +308,24 @@
     EXPECT_EQ(r()->error(), R"(error: binding_array element type must be a sampled texture type)");
 }
 
+TEST_F(ResolverBindingArrayTest, RuntimeBindingArray) {
+    Enable(wgsl::Extension::kChromiumExperimentalDynamicBinding);
+    GlobalVar("a", Binding(0_a), Group(0_a),
+              ty("binding_array", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32())));
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverBindingArrayTest, RuntimeRequiresEnable) {
+    GlobalVar("a", Binding(0_a), Group(0_a),
+              ty("binding_array", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32())));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(error: use of a runtime 'binding_array' requires enabling extension 'chromium_experimental_dynamic_binding')");
+}
+
 // How to test as let / const / return since no constructor?
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 9ce6ca8..a728ce1 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -471,6 +471,16 @@
                          << "language feature, which is not allowed in the current environment";
         return false;
     }
+
+    if (t->Count()->Is<core::type::RuntimeArrayCount>()) {
+        if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalDynamicBinding)) {
+            AddError(source) << "use of a runtime " << style::Attribute("binding_array")
+                             << " requires enabling extension "
+                             << style::Code("chromium_experimental_dynamic_binding");
+            return false;
+        }
+    }
+
     if (!t->Count()->IsAnyOf<core::type::ConstantArrayCount, core::type::RuntimeArrayCount>()) {
         AddError(source) << "binding_array count must be a constant expression";
         return false;
diff --git a/src/tint/lang/wgsl/wgsl.def b/src/tint/lang/wgsl/wgsl.def
index b250427..46bf2c2 100644
--- a/src/tint/lang/wgsl/wgsl.def
+++ b/src/tint/lang/wgsl/wgsl.def
@@ -101,6 +101,8 @@
   chromium_experimental_subgroup_matrix
   // A Chromium-specific extension for barycentric_coord support
   chromium_experimental_barycentric_coord
+  // A Chromium-specific extension for dynamic binding
+  chromium_experimental_dynamic_binding
 }
 
 // https://gpuweb.github.io/gpuweb/wgsl/#language-extensions-sec