Skip to main content

cubecl_tile/tile/
factor.rs

1//! The scale a tile carries ([`Tile::mul`](crate::Tile::mul)): a scale tile windowed with the
2//! values, never applied by the tile itself. The scale tile is a [`Tile`] of its own and may carry
3//! a scale in turn, each covering more than the one inside it: NVFP4's values are under their block
4//! scales, which are under the per-tensor scale.
5
6use std::sync::Arc;
7
8use cubecl::frontend::{AsMutExpand, AsRefExpand, CubeDebug, ExpandTypeClone, IntoExpand, IntoMut};
9use cubecl::ir::{ExpandValue, Scope};
10use cubecl::prelude::*;
11use cubecl::quant::scheme::QuantValue;
12use cubecl::unexpanded;
13use cubecl_std::tensor::layout::Coords2d;
14
15use crate::stage::pipeline::payload::base::{StageOperand, StageSpec, stage_one};
16use crate::*;
17
18/// The scale a tile carries: none, or a scale tile, itself under its own scale or none.
19/// What [`Tile::factor`](crate::Tile::factor) takes out of a tile and
20/// [`Tile::scaled`](crate::Tile::scaled) puts on one.
21#[derive(Clone)]
22pub struct Factor;
23
24#[derive(Clone, Default)]
25pub struct FactorExpand {
26    // `Arc`: a tile holds its scale, and the scale is a tile.
27    scale: Option<Arc<TileExpand>>,
28}
29
30impl Factor {
31    /// No scale: what every operand carries until [`Tile::mul`](crate::Tile::mul).
32    pub(crate) fn none() -> Factor {
33        unexpanded!()
34    }
35
36    /// This factor windowed to `step`, as the values it rides are.
37    pub(crate) fn at(&self, _step: &Step) -> Factor {
38        unexpanded!()
39    }
40
41    /// This factor with every scale that spans `axis` one wide at `coord` along it, as the values
42    /// it rides are ([`Tile::placed_at`](crate::Tile::placed_at)).
43    #[allow(dead_code)] // Reached through its expand, from [`Tile::indexed_at`](crate::Tile::indexed_at).
44    pub(crate) fn placed_at(&self, _axis: Axis, _coord: u32) -> Factor {
45        unexpanded!()
46    }
47
48    /// This factor with every scale that spans `axis` reading the run `[from, until)` along it,
49    /// as the values it rides are ([`Tile::run_within`](crate::Tile::run_within)).
50    #[allow(dead_code)] // Reached through its expand, from [`Tile::indexed_at`](crate::Tile::indexed_at).
51    pub(crate) fn run_within(&self, _axis: Axis, _from: u32, _until: u32) -> Factor {
52        unexpanded!()
53    }
54
55    /// Whether the innermost scales vary along `axis`, so a run along it spans scales.
56    pub(crate) fn varies_along(&self, _axis: Axis) -> bool {
57        unexpanded!()
58    }
59
60    /// The scale covering the value at `coords`: the product down the chain, each scale read
61    /// under `guard`. [`Guard::Proved`] where the reader proved the value's read in bounds, which
62    /// puts the scales covering it in bounds.
63    pub(crate) fn at_coords(&self, _coords: &Coords<u32>, _values: Space, _guard: Guard) -> f32 {
64        unexpanded!()
65    }
66
67    /// The one scale every value shares: the product down the chain, no scale of which varies
68    /// along any axis.
69    pub(crate) fn whole(&self) -> f32 {
70        unexpanded!()
71    }
72
73    /// Whether these values carry a scale at all.
74    pub(crate) fn scaled(&self) -> comptime_type!(bool) {
75        unexpanded!()
76    }
77
78    /// Whether the innermost scales are [words](FactorExpand::holds_words) of block scales.
79    pub(crate) fn holds_words(&self) -> comptime_type!(bool) {
80        unexpanded!()
81    }
82
83    /// The innermost scale tile, without the scale it carries in turn: the block scales an
84    /// encoding copy writes ([`Tile::quantize_from`](crate::Tile::quantize_from)).
85    pub(crate) fn innermost_scale(&self) -> Tile {
86        unexpanded!()
87    }
88
89    /// Every scale outside the innermost, multiplied into one value read at the region's origin.
90    pub(crate) fn coarse(&self) -> f32 {
91        unexpanded!()
92    }
93
94    /// How many scales the chain holds.
95    pub(crate) fn depth(&self) -> comptime_type!(usize) {
96        unexpanded!()
97    }
98
99    /// How the innermost scales sit in their buffer: `None` where these values carry no scale.
100    pub(crate) fn inner_stored(&self) -> comptime_type!(Option<Packing>) {
101        unexpanded!()
102    }
103
104    /// The innermost scales' word at the value at `coords`, read as it is stored.
105    pub(crate) fn word_at(&self, _coords: &Coords<u32>, _values: Space) -> u32 {
106        unexpanded!()
107    }
108
109    /// The innermost scales' load holding the scale covering the value at `coords` written as
110    /// `scales`, the mirror of [`at_coords`](Factor::at_coords): stored plain, or packed as their
111    /// field, as many to a word as it holds (`ue8m0` and `ue4m3` four, `f16` and `bf16` two,
112    /// `f32` one). A word is written whole, so `scales` is its every scale.
113    #[allow(dead_code)] // Reached through its expand, from [`Tile::quantize_from`](crate::Tile::quantize_from).
114    pub(crate) fn write_at<N: Size>(
115        &self,
116        _coords: &Coords<u32>,
117        _values: Space,
118        _scales: Vector<f32, N>,
119    ) {
120        unexpanded!()
121    }
122
123    /// The innermost scales calibrated from `src`, the float values they scale, as burn's
124    /// `quantize_dynamic` calibrates them for values written as `value`: each block's largest
125    /// magnitude over the format's, relative to `coarse`, every scale outside the innermost, where
126    /// there is one. The units that fill the scales take their blocks in turn: lanes a block each,
127    /// meeting through the plane where a word packs several; otherwise a unit a word at a time
128    /// ([`Tile::quantize_from`](crate::Tile::quantize_from)).
129    #[allow(dead_code)] // Reached through its expand, from [`Tile::quantize_from`](crate::Tile::quantize_from).
130    #[allow(clippy::extra_unused_type_parameters)] // `F` is the source's float, which the expand reads.
131    pub(crate) fn calibrate_from<F: Float>(&self, _src: &Tile, _coarse: f32, _value: QuantValue) {
132        unexpanded!()
133    }
134
135    pub(crate) fn __expand_none(_scope: &Scope) -> FactorExpand {
136        FactorExpand::default()
137    }
138}
139
140// A scale is expand-time data, held by one thread: `Arc` as the erased tensors hold theirs.
141#[allow(clippy::arc_with_non_send_sync)]
142impl FactorExpand {
143    /// A factor of `scale`, read at the values' coordinates, under whatever scale it carries.
144    pub(crate) fn of(scale: &TileExpand) -> Self {
145        FactorExpand {
146            scale: Some(Arc::new(scale.clone())),
147        }
148    }
149
150    /// The innermost scale tile, without the scale it carries in turn.
151    pub(crate) fn innermost_tile(&self) -> Option<TileExpand> {
152        self.scale.as_deref().map(|scale| {
153            let mut alone = scale.clone();
154            alone.factor = FactorExpand::default();
155            alone
156        })
157    }
158
159    /// The scale tiles down the chain, innermost first.
160    fn chain(&self) -> impl Iterator<Item = &TileExpand> {
161        std::iter::successors(self.scale.as_deref(), |scale| scale.factor.scale.as_deref())
162    }
163
164    /// Whether `scale`'s own scales vary along an axis outside `space`.
165    fn varies_outside(scope: &Scope, scale: &TileExpand, space: &Space) -> bool {
166        let projection = scale.clone().__expand_projection_method(scope);
167        scale
168            .place
169            .space
170            .axes()
171            .any(|axis| projection.addresses(axis) && !space.contains(axis))
172    }
173
174    /// This factor cut in two: the inner scales, down to the last one that varies along an axis
175    /// outside `space`, and the rest, which vary only along `space`. Each scale covers more than
176    /// the one inside it, so once one varies only along `space`, every one outside it does too.
177    pub(crate) fn split_on(&self, scope: &Scope, space: &Space) -> (FactorExpand, FactorExpand) {
178        let Some(scale) = self.scale.as_deref() else {
179            return (FactorExpand::default(), FactorExpand::default());
180        };
181        if !Self::varies_outside(scope, scale, space) {
182            return (FactorExpand::default(), self.clone());
183        }
184        let (kept, taken) = scale.factor.split_on(scope, space);
185        let mut inner = scale.clone();
186        inner.factor = kept;
187        (FactorExpand::of(&inner), taken)
188    }
189
190    /// This factor with `coarser` outside it: under the last scale of its chain.
191    pub(crate) fn and(&self, coarser: FactorExpand) -> FactorExpand {
192        match self.scale.as_deref() {
193            None => coarser,
194            Some(scale) => {
195                let mut outer = scale.clone();
196                outer.factor = scale.factor.and(coarser);
197                FactorExpand::of(&outer)
198            }
199        }
200    }
201
202    /// Whether these values carry a scale at all.
203    pub(crate) fn scaled(&self) -> bool {
204        self.scale.is_some()
205    }
206
207    /// How many scales the chain holds.
208    pub(crate) fn depth(&self) -> usize {
209        self.chain().count()
210    }
211
212    /// This factor's innermost scale alone.
213    pub(crate) fn innermost(&self) -> FactorExpand {
214        match self.innermost_tile() {
215            Some(scale) => FactorExpand::of(&scale),
216            None => FactorExpand::default(),
217        }
218    }
219
220    /// Every scale outside the innermost, multiplied into one value read at the region's origin.
221    pub(crate) fn coarse(&self, scope: &Scope) -> NativeExpand<f32> {
222        let mut scaled: NativeExpand<f32> =
223            ExpandValue::constant(1u64.into(), f32::elem_type(scope)).into();
224        for scale in self.chain().skip(1) {
225            let origin = origin_of(scope, &scale.place.space);
226            let one = scale_for(scope, scale, &origin, &scale.place.space, Guard::Checked);
227            scaled = MulExpand::__expand_mul_method(scaled, scope, one);
228        }
229        scaled
230    }
231
232    pub(crate) fn __expand_at_method(&self, scope: &Scope, step: &StepExpand) -> FactorExpand {
233        match self.scale.as_deref() {
234            // The scale's own scale is windowed with it, by its `at_step`.
235            Some(scale) => FactorExpand::of(&scale.clone().__expand_at_step_method(scope, step)),
236            None => FactorExpand::default(),
237        }
238    }
239
240    pub(crate) fn __expand_placed_at_method(
241        &self,
242        scope: &Scope,
243        axis: Axis,
244        coord: NativeExpand<u32>,
245    ) -> FactorExpand {
246        self.spanning(axis, |scale| {
247            scale.__expand_placed_at_method(scope, axis, coord)
248        })
249    }
250
251    pub(crate) fn __expand_run_within_method(
252        &self,
253        scope: &Scope,
254        axis: Axis,
255        from: NativeExpand<u32>,
256        until: NativeExpand<u32>,
257    ) -> FactorExpand {
258        self.spanning(axis, |scale| {
259            scale.__expand_run_within_method(scope, axis, from, until)
260        })
261    }
262
263    /// This factor with `place` applied to every scale that spans `axis`, which carries its own
264    /// scales along; the scales that do not span it, as they are.
265    pub(crate) fn spanning(
266        &self,
267        axis: Axis,
268        place: impl Fn(&TileExpand) -> TileExpand,
269    ) -> FactorExpand {
270        match self.scale.as_deref() {
271            None => FactorExpand::default(),
272            Some(scale) if scale.place.space.contains(axis) => FactorExpand::of(&place(scale)),
273            Some(scale) => {
274                let mut kept = scale.clone();
275                kept.factor = scale.factor.spanning(axis, place);
276                FactorExpand::of(&kept)
277            }
278        }
279    }
280
281    pub(crate) fn __expand_at_coords_method(
282        &self,
283        scope: &Scope,
284        coords: &CoordsExpand<u32>,
285        values: Space,
286        guard: Guard,
287    ) -> NativeExpand<f32> {
288        let mut product: Option<NativeExpand<f32>> = None;
289        for scale in self.chain() {
290            assert!(
291                !holds_words(scope, scale),
292                "Factor: these scales are words of four e4m3 block scales, which only the \
293                 block-scaled instruction reads; widened one at a time they mean nothing"
294            );
295            let one = scale_for(scope, scale, coords, &values, guard);
296            product = Some(match product {
297                None => one,
298                Some(product) => MulExpand::__expand_mul_method(product, scope, one),
299            });
300        }
301        product.unwrap_or_else(|| ExpandValue::constant(1u64.into(), f32::elem_type(scope)).into())
302    }
303
304    pub(crate) fn __expand_whole_method(&self, scope: &Scope) -> NativeExpand<f32> {
305        let mut product: NativeExpand<f32> =
306            ExpandValue::constant(1u64.into(), f32::elem_type(scope)).into();
307        for scale in self.chain() {
308            let projection = scale.clone().__expand_projection_method(scope);
309            assert!(
310                scale
311                    .place
312                    .space
313                    .axes()
314                    .all(|axis| !projection.addresses(axis)),
315                "Factor::whole: a scale that varies across the output is applied where the output \
316                 is written through memory, not on the sum's fragments"
317            );
318            let origin = origin_of(scope, &scale.place.space);
319            let one = scale_for(scope, scale, &origin, &scale.place.space, Guard::Checked);
320            product = MulExpand::__expand_mul_method(product, scope, one);
321        }
322        product
323    }
324
325    pub(crate) fn __expand_innermost_scale_method(&self, _scope: &Scope) -> TileExpand {
326        self.innermost_tile()
327            .expect("Tile::quantize_from: the values are written under the block scales they carry")
328    }
329
330    pub(crate) fn __expand_coarse_method(&self, scope: &Scope) -> NativeExpand<f32> {
331        self.coarse(scope)
332    }
333
334    pub(crate) fn __expand_depth_method(&self, _scope: &Scope) -> usize {
335        self.depth()
336    }
337
338    pub(crate) fn __expand_inner_stored_method(&self, scope: &Scope) -> Option<Packing> {
339        self.scale
340            .as_deref()
341            .map(|scale| scale.clone().__expand_packing_method(scope))
342    }
343
344    pub(crate) fn __expand_scaled_method(&self, _scope: &Scope) -> bool {
345        self.scaled()
346    }
347
348    pub(crate) fn __expand_holds_words_method(&self, scope: &Scope) -> bool {
349        self.staged_beside(scope)
350    }
351
352    /// Whether these scales are staged beside the values they scale rather than decoded into
353    /// them: words of block scales, which only the block-scaled instruction reads, so values
354    /// under them are staged as they are stored.
355    pub(crate) fn staged_beside(&self, scope: &Scope) -> bool {
356        self.scale
357            .as_deref()
358            .is_some_and(|scale| holds_words(scope, scale))
359    }
360
361    /// The scale tile staged beside the values, which are under it alone.
362    fn beside(&self) -> &TileExpand {
363        let scale = self
364            .scale
365            .as_deref()
366            .expect("Factor: these values carry no scale to stage beside them");
367        assert!(
368            !scale.factor.scaled(),
369            "Factor: values under words of block scales carry no other scale, since the \
370             block-scaled instruction that reads them holds one; take the coarser one out for the \
371             sum (`Tile::factor`)"
372        );
373        scale
374    }
375
376    /// This factor's stage as `spec` shapes the values': the scales staged beside them, laid out
377    /// plain whatever the values' storage, since no instruction fragment-loads them.
378    pub(crate) fn staged(&self, scope: &Scope, spec: &StageSpec) -> FactorExpand {
379        let spec = StageSpec {
380            storage: StageStorage::Strided,
381            width: None,
382            ..spec.clone()
383        };
384        FactorExpand::of(&stage_one::expand(scope, self.beside(), spec))
385    }
386
387    /// Fill this factor's stage from `src`, the factor it stages windowed as the values are.
388    pub(crate) fn fill_from(&self, scope: &Scope, src: &FactorExpand, meeting: &MeetingExpand) {
389        meeting.__expand_fill_method(scope, &mut self.beside().clone(), src.beside());
390    }
391
392    /// The scales as a slot plans them, beside the values they scale.
393    pub(crate) fn stage_operands(&self, scope: &Scope) -> Vec<StageOperand> {
394        let scale = self.beside();
395        vec![StageOperand {
396            delivery: scale.clone().__expand_delivery_method(scope),
397            space: scale.place.space.clone(),
398            keys: Vec::new(),
399        }]
400    }
401
402    /// Free the shared memory this factor's stage holds.
403    pub(crate) fn free_stage(&self, scope: &Scope) {
404        self.beside().clone().__expand_free_stage_method(scope);
405    }
406
407    pub(crate) fn __expand_word_at_method(
408        &self,
409        scope: &Scope,
410        coords: &CoordsExpand<u32>,
411        values: Space,
412    ) -> NativeExpand<u32> {
413        let scale = self
414            .scale
415            .as_deref()
416            .filter(|scale| holds_words(scope, scale))
417            .expect("Factor::word_at: the innermost scales are no words of block scales");
418        scale
419            .clone()
420            .__expand_scale_for_method::<u32>(scope, coords, values, Guard::Checked)
421    }
422
423    pub(crate) fn __expand_write_at_method<N: Size>(
424        &self,
425        scope: &Scope,
426        coords: &CoordsExpand<u32>,
427        values: Space,
428        scales: NativeExpand<Vector<f32, N>>,
429    ) {
430        let mut scale = self
431            .innermost_tile()
432            .expect("Factor::write_at: these values carry no scale to write");
433        scale.__expand_write_scales_for_method::<N>(scope, coords, values, scales);
434    }
435
436    pub(crate) fn __expand_calibrate_from_method<F: Float>(
437        &self,
438        scope: &Scope,
439        src: &TileExpand,
440        coarse: NativeExpand<f32>,
441        value: QuantValue,
442    ) {
443        let mut scale = self
444            .innermost_tile()
445            .expect("Factor::calibrate_from: these values carry no scale to calibrate");
446        scale.__expand_calibrate_method::<F>(scope, src, coarse, value, self.depth() > 1);
447    }
448}
449
450#[cube]
451impl Tile {
452    /// The load of these scales holding the one covering the value at `coords` of a tile spanning
453    /// `values` written as `scales`, the mirror of [`scale_for`](Tile::scale_for)
454    /// ([`Factor::write_at`]).
455    #[allow(dead_code)] // Reached through its expand, from [`Factor::write_at`].
456    pub(crate) fn write_scales_for<N: Size>(
457        &mut self,
458        coords: &Coords<u32>,
459        #[comptime] values: Space,
460        scales: Vector<f32, N>,
461    ) {
462        let own = self.scale_coords(coords, values);
463        self.write_scales::<N>(&own, scales);
464    }
465
466    /// This tile's load of scales starting at `start` written as `scales`: plain, or packed into
467    /// words as their field.
468    pub(crate) fn write_scales<N: Size>(&mut self, start: &Coords<u32>, scales: Vector<f32, N>) {
469        let space = comptime!(self.place.space.clone());
470        let load = self.vector_tile();
471        let n = N::value();
472        comptime!(assert!(
473            load.values() == n,
474            "Factor::write_at: a load of these scales holds {} of them, not {n}",
475            load.values()
476        ));
477        let at = load.index(start, &space);
478        let packing = self.packing();
479        match comptime!(packing) {
480            Packing::Plain => {
481                let define!(Stored) = self.element;
482                let mut out = self.nd_mut::<Stored, N>();
483                out.write(at, Vector::<Stored, N>::cast_from(scales));
484            }
485            Packing::Packed { field } => {
486                let size!(WP) = comptime!(packing.physical(n));
487                let mut words = self.nd_words_mut::<WP>();
488                words.write(at, pack_line::<WP, N>(scales, field));
489            }
490        }
491    }
492}
493
494/// Whether `scale` holds words rather than scales: each `u32` the `e4m3` scales of the four blocks
495/// one block-scaled instruction step covers, the first block's in the low byte, as an NVFP4
496/// checkpoint packs them, bound plain. Only that instruction reads such scales
497/// ([`FactorExpand::__expand_word_at_method`]); widened to a scale one means nothing. A packed
498/// scale holds `u32` words too, of fields read as scales.
499fn holds_words(scope: &Scope, scale: &TileExpand) -> bool {
500    scale.element == u32::elem_type(scope) && scale.__expand_packing_method(scope) == Packing::Plain
501}
502
503/// The scale of `scale` covering the value at `coords` of a tile spanning `values`, widened to
504/// `f32`, read under `guard`.
505fn scale_for(
506    scope: &Scope,
507    scale: &TileExpand,
508    coords: &CoordsExpand<u32>,
509    values: &Space,
510    guard: Guard,
511) -> NativeExpand<f32> {
512    scale
513        .clone()
514        .__expand_scale_for_method::<f32>(scope, coords, values.clone(), guard)
515}
516
517/// The all-zero coordinate of `space`: where a scale covering a whole region is read.
518fn origin_of(scope: &Scope, space: &Space) -> CoordsExpand<u32> {
519    let mut origin = Coords::<u32>::__expand_new(scope);
520    for _ in 0..space.rank() {
521        let zero: NativeExpand<u32> =
522            ExpandValue::constant(0u64.into(), u32::elem_type(scope)).into();
523        origin.__expand_push_method(scope, zero);
524    }
525    origin
526}
527
528/// A factor as a leaf reads it: the innermost level per line, coarser levels as one value.
529#[derive(CubeType, Clone)]
530#[expand(derive(Clone))]
531pub(crate) struct FactorReader {
532    /// The innermost level, or nothing at all.
533    pub(crate) inner: Factor,
534    /// Every coarser level, already met.
535    pub(crate) coarse: f32,
536    /// The values' space, which a line's `(row, col)` resolves to a coordinate through.
537    #[cube(comptime)]
538    pub(crate) values: Space,
539    #[cube(comptime)]
540    pub(crate) axes: MatrixAxes,
541    #[cube(comptime)]
542    pub(crate) vector_size: usize,
543    /// Whether there is a scale at all.
544    #[cube(comptime)]
545    pub(crate) scaled: bool,
546    /// Which batch matrix the lines are read from.
547    pub(crate) matrix: usize,
548}
549
550#[cube]
551impl FactorReader {
552    /// `value`, the line at `pos` of the values' matrix, under the scale covering it.
553    pub(crate) fn apply<E: Numeric, V: Size>(
554        &self,
555        value: Vector<E, V>,
556        pos: Coords2d,
557    ) -> Vector<E, V> {
558        if comptime!(self.scaled) {
559            let (row, col) = pos;
560            let coords = TileMatrix::value_coords(
561                row,
562                col,
563                self.matrix,
564                comptime!(&self.values),
565                comptime!(self.axes),
566                comptime!(self.vector_size),
567            );
568            self.apply_at::<E, V>(value, &coords)
569        } else {
570            value
571        }
572    }
573
574    /// `value`, the line whose first value lies at `coords`, under the scale covering it.
575    pub(crate) fn apply_at<E: Numeric, V: Size>(
576        &self,
577        value: Vector<E, V>,
578        coords: &Coords<u32>,
579    ) -> Vector<E, V> {
580        if comptime!(self.scaled) {
581            let scale = self.inner.at_coords(
582                coords,
583                comptime!(self.values.clone()),
584                comptime!(Guard::Checked),
585            );
586            // Multiplied in `f32`, rounded to `E` once: a placed `e2m1` value is a lift short, which
587            // the factor carries, and the lift times a scale is past a half's range where its
588            // product with the value is not.
589            let scaled = Vector::<f32, V>::cast_from(value)
590                * Vector::<f32, V>::cast_from(scale * self.coarse);
591            Vector::<E, V>::cast_from(scaled)
592        } else {
593            value
594        }
595    }
596}
597
598impl FactorExpand {
599    pub(crate) fn __expand_varies_along_method(&self, scope: &Scope, axis: Axis) -> bool {
600        self.scale.as_deref().is_some_and(|scale| {
601            scale
602                .clone()
603                .__expand_projection_method(scope)
604                .addresses(axis)
605        })
606    }
607}
608
609impl CubeType for Factor {
610    type ExpandType = FactorExpand;
611}
612impl IntoExpand for FactorExpand {
613    type Expand = Self;
614    fn into_expand(self, _: &Scope) -> Self {
615        self
616    }
617}
618impl ExpandTypeClone for FactorExpand {
619    fn clone_unchecked(&self) -> Self {
620        self.clone()
621    }
622}
623impl IntoMut for FactorExpand {
624    fn into_mut(self, _: &Scope) -> Self {
625        self
626    }
627}
628impl CubeDebug for FactorExpand {}
629impl AsRefExpand for FactorExpand {
630    fn __expand_ref_method(&self, _: &Scope) -> &Self {
631        self
632    }
633}
634impl AsMutExpand for FactorExpand {
635    fn __expand_ref_mut_method(&mut self, _: &Scope) -> &mut Self {
636        self
637    }
638}