Skip to main content

cairo_lang_semantic/
substitution.rs

1use std::hash::Hash;
2use std::ops::{Deref, DerefMut};
3
4use cairo_lang_defs::ids::{
5    EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, GenericParamId, ImplAliasId, ImplDefId,
6    ImplFunctionId, ImplImplDefId, LanguageElementId, LocalVarId, MemberId, ParamId, StructId,
7    TraitConstantId, TraitFunctionId, TraitId, TraitImplId, TraitTypeId, VariantId,
8};
9use cairo_lang_diagnostics::{DiagnosticAdded, Maybe, skip_diagnostic};
10use cairo_lang_utils::deque::Deque;
11use cairo_lang_utils::extract_matches;
12use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
13use itertools::zip_eq;
14use salsa::Database;
15
16use crate::expr::inference::canonic::CanonicalTrait;
17use crate::expr::inference::{
18    ConstVar, ImplVar, ImplVarId, ImplVarTraitItemMappings, InferenceId, InferenceVar,
19    LocalConstVarId, LocalImplVarId, LocalNegativeImplVarId, LocalTypeVarId, NegativeImplVar,
20    NegativeImplVarId, TypeVar,
21};
22use crate::items::constant::{ConstValue, ConstValueId, ImplConstantId};
23use crate::items::functions::{
24    ConcreteFunctionWithBody, ConcreteFunctionWithBodyId, GenericFunctionId,
25    GenericFunctionWithBodyId, ImplFunctionBodyId, ImplGenericFunctionId,
26    ImplGenericFunctionWithBodyId,
27};
28use crate::items::generics::{GenericParamConst, GenericParamImpl, GenericParamType};
29use crate::items::imp::{
30    GeneratedImplId, GeneratedImplItems, GeneratedImplLongId, ImplId, ImplImplId, ImplLongId,
31    ImplSemantic, NegativeImplId, NegativeImplLongId, UninferredGeneratedImplId,
32    UninferredGeneratedImplLongId, UninferredImpl,
33};
34use crate::items::trt::{
35    ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId, ConcreteTraitTypeId,
36    ConcreteTraitTypeLongId,
37};
38use crate::types::{
39    ClosureTypeLongId, ConcreteEnumLongId, ConcreteExternTypeLongId, ConcreteStructLongId,
40    ImplTypeId,
41};
42use crate::{
43    ConcreteEnumId, ConcreteExternTypeId, ConcreteFunction, ConcreteImplId, ConcreteImplLongId,
44    ConcreteStructId, ConcreteTraitId, ConcreteTraitLongId, ConcreteTypeId, ConcreteVariant,
45    ExprId, ExprVar, ExprVarMemberPath, FunctionId, FunctionLongId, GenericArgumentId,
46    GenericParam, MatchArmSelector, MemberAccessKind, Parameter, Signature, TypeId, TypeLongId,
47    ValueSelectorArm, VarId,
48};
49
50pub enum RewriteResult {
51    Modified,
52    NoChange,
53}
54
55/// A substitution of generic arguments in generic parameters as well as the `Self` of traits. Used
56/// for concretization.
57#[derive(Clone, Debug, Default, PartialEq, Eq, salsa::Update, Hash)]
58pub struct GenericSubstitution<'db> {
59    pub param_to_arg: OrderedHashMap<GenericParamId<'db>, GenericArgumentId<'db>>,
60    pub self_impl: Option<ImplId<'db>>,
61}
62impl<'db> GenericSubstitution<'db> {
63    pub fn from_impl(self_impl: ImplId<'db>) -> Self {
64        GenericSubstitution { param_to_arg: OrderedHashMap::default(), self_impl: Some(self_impl) }
65    }
66    pub fn new(
67        generic_params: &[GenericParam<'db>],
68        generic_args: &[GenericArgumentId<'db>],
69    ) -> Self {
70        GenericSubstitution {
71            param_to_arg: zip_eq(generic_params, generic_args)
72                .map(|(param, arg)| (param.id(), *arg))
73                .collect(),
74            self_impl: None,
75        }
76    }
77    pub fn concat(mut self, other: GenericSubstitution<'db>) -> Self {
78        for (key, value) in other.param_to_arg {
79            self.param_to_arg.insert(key, value);
80        }
81        if let Some(self_impl) = other.self_impl {
82            self.self_impl = Some(self_impl);
83        }
84        self
85    }
86    /// Returns whether the substitution is empty.
87    pub fn is_empty(&self) -> bool {
88        self.param_to_arg.is_empty() && self.self_impl.is_none()
89    }
90    pub fn substitute<'a, 'r, Obj>(&'r self, db: &'a dyn Database, obj: Obj) -> Maybe<Obj>
91    where
92        'a: 'r,
93        'db: 'a,
94        SubstitutionRewriter<'a, 'r>: SemanticRewriter<Obj, DiagnosticAdded>,
95    {
96        if self.is_empty() {
97            Ok(obj)
98        } else {
99            SubstitutionRewriter { db, substitution: self }.rewrite(obj)
100        }
101    }
102}
103impl<'db> Deref for GenericSubstitution<'db> {
104    type Target = OrderedHashMap<GenericParamId<'db>, GenericArgumentId<'db>>;
105
106    fn deref(&self) -> &Self::Target {
107        &self.param_to_arg
108    }
109}
110impl<'db> DerefMut for GenericSubstitution<'db> {
111    fn deref_mut(&mut self) -> &mut Self::Target {
112        &mut self.param_to_arg
113    }
114}
115
116#[macro_export]
117macro_rules! semantic_object_for_id {
118    ($name:ident, $long_ty:path) => {
119        impl<
120            'a,
121            Error,
122            TRewriter: $crate::substitution::HasDb<&'a dyn Database>
123                + $crate::substitution::SemanticRewriter<$long_ty, Error>,
124        > $crate::substitution::SemanticObject<TRewriter, Error> for $name<'a>
125        {
126            fn default_rewrite(
127                &mut self,
128                rewriter: &mut TRewriter,
129            ) -> Result<$crate::substitution::RewriteResult, Error> where {
130                let db = $crate::substitution::HasDb::get_db(rewriter);
131                let mut val = self.long(db).clone();
132                Ok(
133                    match $crate::substitution::SemanticRewriter::internal_rewrite(
134                        rewriter, &mut val,
135                    )? {
136                        $crate::substitution::RewriteResult::Modified => {
137                            *self = $name::new(db, val);
138                            $crate::substitution::RewriteResult::Modified
139                        }
140                        $crate::substitution::RewriteResult::NoChange => {
141                            $crate::substitution::RewriteResult::NoChange
142                        }
143                    },
144                )
145            }
146        }
147    };
148}
149
150#[macro_export]
151macro_rules! add_rewrite {
152    (<$($generics:lifetime),*>, $self_ty:ty, $err_ty:ty, $ty:path) => {
153        impl <$($generics),*> SemanticRewriter<$ty, $err_ty> for $self_ty {
154            fn internal_rewrite(
155                &mut self,
156                value: &mut $ty
157            ) -> Result<$crate::substitution::RewriteResult, $err_ty> {
158                $crate::substitution::SemanticObject::default_rewrite(value, self)
159            }
160        }
161    };
162}
163
164#[macro_export]
165macro_rules! add_rewrite_identity {
166    (<$($generics:lifetime),*>, $self_ty:ty, $err_ty:ty, $ty:path) => {
167        impl <$($generics),*> SemanticRewriter<$ty, $err_ty> for $self_ty {
168            fn internal_rewrite(
169                &mut self,
170                _value: &mut $ty
171            ) -> Result<$crate::substitution::RewriteResult, $err_ty> {
172                Ok(RewriteResult::NoChange)
173            }
174        }
175    };
176}
177
178pub trait SemanticObject<TRewriter, Error>: Sized {
179    fn default_rewrite(&mut self, rewriter: &mut TRewriter) -> Result<RewriteResult, Error>;
180}
181impl<T, E, TRewriter: SemanticRewriter<T, E>> SemanticRewriter<Vec<T>, E> for TRewriter {
182    fn internal_rewrite(&mut self, value: &mut Vec<T>) -> Result<RewriteResult, E> {
183        let mut result = RewriteResult::NoChange;
184        for el in value.iter_mut() {
185            match self.internal_rewrite(el)? {
186                RewriteResult::Modified => {
187                    result = RewriteResult::Modified;
188                }
189                RewriteResult::NoChange => {}
190            }
191        }
192
193        Ok(result)
194    }
195}
196impl<T, E, TRewriter: SemanticRewriter<T, E>> SemanticRewriter<Deque<T>, E> for TRewriter {
197    fn internal_rewrite(&mut self, value: &mut Deque<T>) -> Result<RewriteResult, E> {
198        let mut result = RewriteResult::NoChange;
199        for el in value.iter_mut() {
200            match self.internal_rewrite(el)? {
201                RewriteResult::Modified => {
202                    result = RewriteResult::Modified;
203                }
204                RewriteResult::NoChange => {}
205            }
206        }
207
208        Ok(result)
209    }
210}
211impl<T, E, TRewriter: SemanticRewriter<T, E>> SemanticRewriter<Box<T>, E> for TRewriter {
212    fn internal_rewrite(&mut self, value: &mut Box<T>) -> Result<RewriteResult, E> {
213        self.internal_rewrite(value.as_mut())
214    }
215}
216
217impl<'a, K: Hash + Eq + LanguageElementId<'a>, V: Clone, E, TRewriter: SemanticRewriter<V, E>>
218    SemanticRewriter<OrderedHashMap<K, V>, E> for TRewriter
219{
220    fn internal_rewrite(&mut self, value: &mut OrderedHashMap<K, V>) -> Result<RewriteResult, E> {
221        let mut result = RewriteResult::NoChange;
222        for (_, v) in value.iter_mut() {
223            match self.internal_rewrite(v)? {
224                RewriteResult::Modified => {
225                    result = RewriteResult::Modified;
226                }
227                RewriteResult::NoChange => {}
228            }
229        }
230        Ok(result)
231    }
232}
233impl<T0, T1, E, TRewriter: SemanticRewriter<T0, E> + SemanticRewriter<T1, E>>
234    SemanticRewriter<(T0, T1), E> for TRewriter
235{
236    fn internal_rewrite(&mut self, value: &mut (T0, T1)) -> Result<RewriteResult, E> {
237        match (self.internal_rewrite(&mut value.0)?, self.internal_rewrite(&mut value.1)?) {
238            (RewriteResult::NoChange, RewriteResult::NoChange) => Ok(RewriteResult::NoChange),
239            _ => Ok(RewriteResult::Modified),
240        }
241    }
242}
243impl<T, E, TRewriter: SemanticRewriter<T, E>> SemanticRewriter<Option<T>, E> for TRewriter {
244    fn internal_rewrite(&mut self, value: &mut Option<T>) -> Result<RewriteResult, E> {
245        Ok(match value {
246            Some(val) => self.internal_rewrite(val)?,
247            None => RewriteResult::NoChange,
248        })
249    }
250}
251impl<T, E, TRewriter: SemanticRewriter<T, E>, E2> SemanticRewriter<Result<T, E2>, E> for TRewriter {
252    fn internal_rewrite(&mut self, value: &mut Result<T, E2>) -> Result<RewriteResult, E> {
253        Ok(match value {
254            Ok(val) => self.internal_rewrite(val)?,
255            Err(_) => RewriteResult::NoChange,
256        })
257    }
258}
259pub trait HasDb<T> {
260    fn get_db(&self) -> T;
261}
262pub trait SemanticRewriter<T, Error> {
263    fn rewrite(&mut self, mut value: T) -> Result<T, Error> {
264        self.internal_rewrite(&mut value)?;
265        Ok(value)
266    }
267
268    fn internal_rewrite(&mut self, value: &mut T) -> Result<RewriteResult, Error>;
269}
270
271#[macro_export]
272macro_rules! prune_single {
273    ($macro:ident, $item:ident, ) => {$macro!($item);};
274    ($macro:ident, $item:ident, $item0:ident $($item_rest:ident)*) => {
275        macro_rules! __inner_helper {
276            // Identifiers equal, skip.
277            ($item $item) => { };
278            // Identifiers not equal, continue scanning.
279            ($item $item0) => { $crate::prune_single!($macro, $item, $($item_rest)*); };
280        }
281        __inner_helper!($item $item0);
282    }
283}
284
285#[macro_export]
286macro_rules! add_basic_rewrites {
287    (<$($generics:lifetime),*>, $self_ty:ty, $err_ty:ty, @exclude $($exclude:ident)*) => {
288        // TODO(eytan-starkware) Cleanup to a single macro that deals with generics as an input
289        macro_rules! __identity_helper {
290            ($item:ident) => {
291                $crate::add_rewrite_identity!(<$($generics),*>, $self_ty, $err_ty, $item<'a>);
292            }
293        }
294        macro_rules! __identity_helper_no_lifetime {
295            ($item:ident) => {
296                $crate::add_rewrite_identity!(<$($generics),*>, $self_ty, $err_ty, $item);
297            }
298        }
299        macro_rules! __regular_helper {
300            ($item:ident) => { $crate::add_rewrite!(<$($generics),*>, $self_ty, $err_ty, $item<'a>); }
301        }
302        macro_rules! __regular_helper_no_lifetime {
303            ($item:ident) => { $crate::add_rewrite!(<$($generics),*>, $self_ty, $err_ty, $item); }
304        }
305
306        $crate::prune_single!(__identity_helper, InferenceId, $($exclude)*);
307        $crate::prune_single!(__identity_helper, ParamId, $($exclude)*);
308        $crate::prune_single!(__identity_helper, FreeFunctionId, $($exclude)*);
309        $crate::prune_single!(__identity_helper, ExternFunctionId, $($exclude)*);
310        $crate::prune_single!(__identity_helper, ExternTypeId, $($exclude)*);
311        $crate::prune_single!(__identity_helper, ImplDefId, $($exclude)*);
312        $crate::prune_single!(__identity_helper, ImplImplDefId, $($exclude)*);
313        $crate::prune_single!(__identity_helper, ImplAliasId, $($exclude)*);
314        $crate::prune_single!(__identity_helper, TraitId, $($exclude)*);
315        $crate::prune_single!(__identity_helper, TraitFunctionId, $($exclude)*);
316        $crate::prune_single!(__identity_helper, VariantId, $($exclude)*);
317        $crate::prune_single!(__identity_helper, ImplFunctionId, $($exclude)*);
318        $crate::prune_single!(__identity_helper, EnumId, $($exclude)*);
319        $crate::prune_single!(__identity_helper, StructId, $($exclude)*);
320        $crate::prune_single!(__identity_helper, GenericParamId, $($exclude)*);
321        $crate::prune_single!(__identity_helper, TraitTypeId, $($exclude)*);
322        $crate::prune_single!(__identity_helper, TraitImplId, $($exclude)*);
323        $crate::prune_single!(__identity_helper, TraitConstantId, $($exclude)*);
324        $crate::prune_single!(__identity_helper, TypeVar, $($exclude)*);
325        $crate::prune_single!(__identity_helper, ConstVar, $($exclude)*);
326        $crate::prune_single!(__identity_helper, VarId, $($exclude)*);
327        $crate::prune_single!(__identity_helper, MemberId, $($exclude)*);
328        $crate::prune_single!(__identity_helper, LocalVarId, $($exclude)*);
329        $crate::prune_single!(__identity_helper_no_lifetime, LocalImplVarId, $($exclude)*);
330        $crate::prune_single!(__identity_helper_no_lifetime, LocalTypeVarId, $($exclude)*);
331        $crate::prune_single!(__identity_helper_no_lifetime, LocalConstVarId, $($exclude)*);
332        $crate::prune_single!(__identity_helper_no_lifetime, LocalNegativeImplVarId, $($exclude)*);
333        $crate::prune_single!(__identity_helper_no_lifetime, InferenceVar, $($exclude)*);
334        $crate::prune_single!(__identity_helper, ImplFunctionBodyId, $($exclude)*);
335        $crate::prune_single!(__identity_helper_no_lifetime, ExprId, $($exclude)*);
336
337        $crate::prune_single!(__regular_helper, Signature, $($exclude)*);
338        $crate::prune_single!(__regular_helper, GenericFunctionId, $($exclude)*);
339        $crate::prune_single!(__regular_helper, GenericFunctionWithBodyId, $($exclude)*);
340        $crate::prune_single!(__regular_helper, ConcreteFunction, $($exclude)*);
341        $crate::prune_single!(__regular_helper, ConcreteFunctionWithBody, $($exclude)*);
342        $crate::prune_single!(__regular_helper, ConcreteFunctionWithBodyId, $($exclude)*);
343        $crate::prune_single!(__regular_helper, ImplGenericFunctionId, $($exclude)*);
344        $crate::prune_single!(__regular_helper, ImplGenericFunctionWithBodyId, $($exclude)*);
345        $crate::prune_single!(__regular_helper, ImplVar, $($exclude)*);
346        $crate::prune_single!(__regular_helper, ImplVarId, $($exclude)*);
347        $crate::prune_single!(__regular_helper, NegativeImplVar, $($exclude)*);
348        $crate::prune_single!(__regular_helper, NegativeImplVarId, $($exclude)*);
349        $crate::prune_single!(__regular_helper, Parameter, $($exclude)*);
350        $crate::prune_single!(__regular_helper, GenericParam, $($exclude)*);
351        $crate::prune_single!(__regular_helper, GenericParamType, $($exclude)*);
352        $crate::prune_single!(__regular_helper, GenericParamConst, $($exclude)*);
353        $crate::prune_single!(__regular_helper, GenericParamImpl, $($exclude)*);
354        $crate::prune_single!(__regular_helper, GenericArgumentId, $($exclude)*);
355        $crate::prune_single!(__regular_helper, FunctionId, $($exclude)*);
356        $crate::prune_single!(__regular_helper, FunctionLongId, $($exclude)*);
357        $crate::prune_single!(__regular_helper, TypeId, $($exclude)*);
358        $crate::prune_single!(__regular_helper, TypeLongId, $($exclude)*);
359        $crate::prune_single!(__regular_helper, ConstValueId, $($exclude)*);
360        $crate::prune_single!(__regular_helper, ConstValue, $($exclude)*);
361        $crate::prune_single!(__regular_helper, ConcreteVariant, $($exclude)*);
362        $crate::prune_single!(__regular_helper_no_lifetime, ValueSelectorArm, $($exclude)*);
363        $crate::prune_single!(__regular_helper, MatchArmSelector, $($exclude)*);
364        $crate::prune_single!(__regular_helper, ClosureTypeLongId, $($exclude)*);
365        $crate::prune_single!(__regular_helper, ConcreteTypeId, $($exclude)*);
366        $crate::prune_single!(__regular_helper, ConcreteStructId, $($exclude)*);
367        $crate::prune_single!(__regular_helper, ConcreteStructLongId, $($exclude)*);
368        $crate::prune_single!(__regular_helper, ConcreteEnumId, $($exclude)*);
369        $crate::prune_single!(__regular_helper, ConcreteEnumLongId, $($exclude)*);
370        $crate::prune_single!(__regular_helper, ConcreteExternTypeId, $($exclude)*);
371        $crate::prune_single!(__regular_helper, ConcreteExternTypeLongId, $($exclude)*);
372        $crate::prune_single!(__regular_helper, ConcreteTraitId, $($exclude)*);
373        $crate::prune_single!(__regular_helper, ConcreteTraitLongId, $($exclude)*);
374        $crate::prune_single!(__regular_helper, ConcreteTraitTypeId, $($exclude)*);
375        $crate::prune_single!(__regular_helper, ConcreteTraitTypeLongId, $($exclude)*);
376        $crate::prune_single!(__regular_helper, ConcreteImplId, $($exclude)*);
377        $crate::prune_single!(__regular_helper, ConcreteImplLongId, $($exclude)*);
378        $crate::prune_single!(__regular_helper, ConcreteTraitGenericFunctionLongId, $($exclude)*);
379        $crate::prune_single!(__regular_helper, ConcreteTraitGenericFunctionId, $($exclude)*);
380        $crate::prune_single!(__regular_helper, GeneratedImplId, $($exclude)*);
381        $crate::prune_single!(__regular_helper, GeneratedImplLongId, $($exclude)*);
382        $crate::prune_single!(__regular_helper, GeneratedImplItems, $($exclude)*);
383        $crate::prune_single!(__regular_helper, ImplLongId, $($exclude)*);
384        $crate::prune_single!(__regular_helper, ImplId, $($exclude)*);
385        $crate::prune_single!(__regular_helper, NegativeImplLongId, $($exclude)*);
386        $crate::prune_single!(__regular_helper, NegativeImplId, $($exclude)*);
387        $crate::prune_single!(__regular_helper, ImplTypeId, $($exclude)*);
388        $crate::prune_single!(__regular_helper, ImplConstantId, $($exclude)*);
389        $crate::prune_single!(__regular_helper, ImplImplId, $($exclude)*);
390        $crate::prune_single!(__regular_helper, UninferredGeneratedImplId, $($exclude)*);
391        $crate::prune_single!(__regular_helper, UninferredGeneratedImplLongId, $($exclude)*);
392        $crate::prune_single!(__regular_helper, UninferredImpl, $($exclude)*);
393        $crate::prune_single!(__regular_helper, ExprVarMemberPath, $($exclude)*);
394        $crate::prune_single!(__regular_helper, MemberAccessKind, $($exclude)*);
395        $crate::prune_single!(__regular_helper, ExprVar, $($exclude)*);
396        $crate::prune_single!(__regular_helper, ImplVarTraitItemMappings, $($exclude)*);
397        $crate::prune_single!(__regular_helper, CanonicalTrait, $($exclude)*);
398    };
399}
400
401#[macro_export]
402macro_rules! add_expr_rewrites {
403    (<$($generics:lifetime),*>, $self_ty:ty, $err_ty:ty, @exclude $($exclude:ident)*) => {
404        macro_rules! __identity_helper {
405            ($item:ident) => {
406                 $crate::add_rewrite_identity!(<$($generics),*>, $self_ty, $err_ty, $item<'a>);
407            }
408        }
409        macro_rules! __identity_helper_no_lifetime {
410            ($item:ident) => {
411                $crate::add_rewrite_identity!(<$($generics),*>, $self_ty, $err_ty, $item);
412            }
413        }
414        macro_rules! __regular_helper {
415            ($item:ident) => { $crate::add_rewrite!(<$($generics),*>, $self_ty, $err_ty, $item<'a>); }
416        }
417        macro_rules! __regular_helper_no_lifetime {
418            ($item:ident) => { $crate::add_rewrite!(<$($generics),*>, $self_ty, $err_ty, $item); }
419        }
420
421        $crate::prune_single!(__identity_helper_no_lifetime, PatternId, $($exclude)*);
422        $crate::prune_single!(__identity_helper_no_lifetime, StatementId, $($exclude)*);
423        $crate::prune_single!(__identity_helper, ConstantId, $($exclude)*);
424        $crate::prune_single!(__regular_helper, Expr, $($exclude)*);
425        $crate::prune_single!(__regular_helper, ExprTuple, $($exclude)*);
426        $crate::prune_single!(__regular_helper, ExprSnapshot, $($exclude)*);
427        $crate::prune_single!(__regular_helper, ExprDesnap, $($exclude)*);
428        $crate::prune_single!(__regular_helper, ExprAssignment, $($exclude)*);
429        $crate::prune_single!(__regular_helper, ExprLogicalOperator, $($exclude)*);
430        $crate::prune_single!(__regular_helper, ExprBlock, $($exclude)*);
431        $crate::prune_single!(__regular_helper, ExprFunctionCall, $($exclude)*);
432        $crate::prune_single!(__regular_helper, ExprMatch, $($exclude)*);
433        $crate::prune_single!(__regular_helper, ExprIf, $($exclude)*);
434        $crate::prune_single!(__regular_helper_no_lifetime, Condition, $($exclude)*);
435        $crate::prune_single!(__regular_helper, ExprLoop, $($exclude)*);
436        $crate::prune_single!(__regular_helper, ExprWhile, $($exclude)*);
437        $crate::prune_single!(__regular_helper, ExprFor, $($exclude)*);
438        $crate::prune_single!(__regular_helper, ExprNumericLiteral, $($exclude)*);
439        $crate::prune_single!(__regular_helper, ExprStringLiteral, $($exclude)*);
440        $crate::prune_single!(__regular_helper, ExprMemberAccess, $($exclude)*);
441        $crate::prune_single!(__regular_helper, ExprStructCtor, $($exclude)*);
442        $crate::prune_single!(__regular_helper, ExprEnumVariantCtor, $($exclude)*);
443        $crate::prune_single!(__regular_helper, ExprPropagateError, $($exclude)*);
444        $crate::prune_single!(__regular_helper, ExprConstant, $($exclude)*);
445        $crate::prune_single!(__regular_helper, ExprFixedSizeArray, $($exclude)*);
446        $crate::prune_single!(__regular_helper, ExprClosure, $($exclude)*);
447        $crate::prune_single!(__regular_helper, ExprMissing, $($exclude)*);
448        $crate::prune_single!(__regular_helper, ExprFunctionCallArg, $($exclude)*);
449        $crate::prune_single!(__regular_helper, FixedSizeArrayItems, $($exclude)*);
450        $crate::prune_single!(__regular_helper_no_lifetime, MatchArm, $($exclude)*);
451        $crate::prune_single!(__regular_helper, Statement, $($exclude)*);
452        $crate::prune_single!(__regular_helper, StatementExpr, $($exclude)*);
453        $crate::prune_single!(__regular_helper, StatementLet, $($exclude)*);
454        $crate::prune_single!(__regular_helper, StatementReturn, $($exclude)*);
455        $crate::prune_single!(__regular_helper, StatementContinue, $($exclude)*);
456        $crate::prune_single!(__regular_helper, StatementBreak, $($exclude)*);
457        $crate::prune_single!(__regular_helper, StatementItem, $($exclude)*);
458        $crate::prune_single!(__regular_helper, Pattern, $($exclude)*);
459        $crate::prune_single!(__regular_helper, PatternLiteral, $($exclude)*);
460        $crate::prune_single!(__regular_helper, PatternStringLiteral, $($exclude)*);
461        $crate::prune_single!(__regular_helper, PatternVariable, $($exclude)*);
462        $crate::prune_single!(__regular_helper, PatternStruct, $($exclude)*);
463        $crate::prune_single!(__regular_helper, PatternTuple, $($exclude)*);
464        $crate::prune_single!(__regular_helper, PatternFixedSizeArray, $($exclude)*);
465        $crate::prune_single!(__regular_helper, PatternEnumVariant, $($exclude)*);
466        $crate::prune_single!(__regular_helper, PatternOtherwise, $($exclude)*);
467        $crate::prune_single!(__regular_helper, PatternMissing, $($exclude)*);
468        $crate::prune_single!(__regular_helper, LocalVariable, $($exclude)*);
469        $crate::prune_single!(__regular_helper, Member, $($exclude)*);
470    };
471}
472
473pub struct SubstitutionRewriter<'a, 'r> {
474    db: &'a dyn Database,
475    substitution: &'r GenericSubstitution<'a>,
476}
477impl<'a> HasDb<&'a dyn Database> for SubstitutionRewriter<'a, '_> {
478    fn get_db(&self) -> &'a dyn Database {
479        self.db
480    }
481}
482
483add_basic_rewrites!(
484    <'a, 'r>,
485    SubstitutionRewriter<'a, 'r>,
486    DiagnosticAdded,
487    @exclude TypeId TypeLongId ImplId ImplLongId ConstValue GenericFunctionWithBodyId NegativeImplId NegativeImplLongId
488);
489
490impl<'db> SemanticRewriter<TypeId<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
491    fn internal_rewrite(&mut self, value: &mut TypeId<'db>) -> Maybe<RewriteResult> {
492        if value.is_fully_concrete(self.db) {
493            return Ok(RewriteResult::NoChange);
494        }
495        value.default_rewrite(self)
496    }
497}
498
499impl<'db> SemanticRewriter<ImplId<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
500    fn internal_rewrite(&mut self, value: &mut ImplId<'db>) -> Maybe<RewriteResult> {
501        if value.is_fully_concrete(self.db) {
502            return Ok(RewriteResult::NoChange);
503        }
504        value.default_rewrite(self)
505    }
506}
507
508impl<'db> SemanticRewriter<NegativeImplId<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
509    fn internal_rewrite(&mut self, value: &mut NegativeImplId<'db>) -> Maybe<RewriteResult> {
510        if value.is_fully_concrete(self.db) {
511            return Ok(RewriteResult::NoChange);
512        }
513        value.default_rewrite(self)
514    }
515}
516
517impl<'db> SemanticRewriter<TypeLongId<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
518    fn internal_rewrite(&mut self, value: &mut TypeLongId<'db>) -> Maybe<RewriteResult> {
519        match value {
520            TypeLongId::GenericParameter(generic_param) => {
521                if let Some(generic_arg) = self.substitution.get(generic_param) {
522                    let GenericArgumentId::Type(type_id) = generic_arg else {
523                        // The generic arg kind doesn't match the type parameter; a diagnostic
524                        // (WrongGenericParamKindForImplFunction) was already reported.
525                        return Err(skip_diagnostic());
526                    };
527                    // return self.rewrite(type_id.long(self.db));
528                    *value = type_id.long(self.db).clone();
529                    return Ok(RewriteResult::Modified);
530                }
531            }
532            TypeLongId::ImplType(impl_type_id) => {
533                let impl_type_id_rewrite_result = self.internal_rewrite(impl_type_id)?;
534                let new_value = self.db.impl_type_concrete_implized(*impl_type_id)?.long(self.db);
535                if *new_value != *value {
536                    *value = new_value.clone();
537                    return Ok(RewriteResult::Modified);
538                } else {
539                    return Ok(impl_type_id_rewrite_result);
540                }
541            }
542            _ => {}
543        }
544        value.default_rewrite(self)
545    }
546}
547impl<'db> SemanticRewriter<ConstValue<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
548    fn internal_rewrite(&mut self, value: &mut ConstValue<'db>) -> Maybe<RewriteResult> {
549        match value {
550            ConstValue::Generic(param_id) => {
551                if let Some(generic_arg) = self.substitution.get(param_id) {
552                    let const_value_id = extract_matches!(generic_arg, GenericArgumentId::Constant);
553
554                    *value = const_value_id.long(self.db).clone();
555                    return Ok(RewriteResult::Modified);
556                }
557            }
558            ConstValue::ImplConstant(impl_constant_id) => {
559                let impl_const_id_rewrite_result = self.internal_rewrite(impl_constant_id)?;
560                let new_value =
561                    self.db.impl_constant_concrete_implized_value(*impl_constant_id)?.long(self.db);
562                if *new_value != *value {
563                    *value = new_value.clone();
564                    return Ok(RewriteResult::Modified);
565                } else {
566                    return Ok(impl_const_id_rewrite_result);
567                }
568            }
569            _ => {}
570        }
571
572        value.default_rewrite(self)
573    }
574}
575impl<'db> SemanticRewriter<ImplLongId<'db>, DiagnosticAdded> for SubstitutionRewriter<'db, '_> {
576    fn internal_rewrite(&mut self, value: &mut ImplLongId<'db>) -> Maybe<RewriteResult> {
577        match value {
578            ImplLongId::GenericParameter(generic_param) => {
579                if let Some(generic_arg) = self.substitution.get(generic_param) {
580                    *value = extract_matches!(generic_arg, GenericArgumentId::Impl)
581                        .long(self.db)
582                        .clone();
583                    // TODO(GIL): Reduce and check for cycles when the substitution is created.
584                    // Substitution is guaranteed to not contain its own variables.
585                    return Ok(RewriteResult::Modified);
586                }
587            }
588            ImplLongId::ImplImpl(impl_impl_id) => {
589                let impl_impl_id_rewrite_result = self.internal_rewrite(impl_impl_id)?;
590                let new_value = self.db.impl_impl_concrete_implized(*impl_impl_id)?.long(self.db);
591                if *new_value != *value {
592                    *value = new_value.clone();
593                    return Ok(RewriteResult::Modified);
594                } else {
595                    return Ok(impl_impl_id_rewrite_result);
596                }
597            }
598            ImplLongId::SelfImpl(concrete_trait_id) => {
599                let rewrite_result = self.internal_rewrite(concrete_trait_id)?;
600                if let Some(self_impl) = &self.substitution.self_impl {
601                    if *concrete_trait_id == self_impl.concrete_trait(self.db)? {
602                        *value = self_impl.long(self.db).clone();
603                        return Ok(RewriteResult::Modified);
604                    }
605                } else {
606                    return Ok(rewrite_result);
607                }
608            }
609            _ => {}
610        }
611        value.default_rewrite(self)
612    }
613}
614
615impl<'db> SemanticRewriter<NegativeImplLongId<'db>, DiagnosticAdded>
616    for SubstitutionRewriter<'db, '_>
617{
618    fn internal_rewrite(&mut self, value: &mut NegativeImplLongId<'db>) -> Maybe<RewriteResult> {
619        if let NegativeImplLongId::GenericParameter(generic_param) = value
620            && let Some(generic_arg) = self.substitution.get(generic_param)
621        {
622            *value =
623                extract_matches!(generic_arg, GenericArgumentId::NegImpl).long(self.db).clone();
624            return Ok(RewriteResult::Modified);
625        }
626
627        value.default_rewrite(self)
628    }
629}
630
631impl<'db> SemanticRewriter<GenericFunctionWithBodyId<'db>, DiagnosticAdded>
632    for SubstitutionRewriter<'db, '_>
633{
634    fn internal_rewrite(
635        &mut self,
636        value: &mut GenericFunctionWithBodyId<'db>,
637    ) -> Maybe<RewriteResult> {
638        if let GenericFunctionWithBodyId::Trait(id) = value
639            && let Some(self_impl) = &self.substitution.self_impl
640            && let ImplLongId::Concrete(concrete_impl_id) = self_impl.long(self.db)
641            && self.rewrite(id.concrete_trait(self.db))? == self_impl.concrete_trait(self.db)?
642        {
643            *value = GenericFunctionWithBodyId::Impl(ImplGenericFunctionWithBodyId {
644                concrete_impl_id: *concrete_impl_id,
645                function_body: ImplFunctionBodyId::Trait(id.trait_function(self.db)),
646            });
647            return Ok(RewriteResult::Modified);
648        }
649        value.default_rewrite(self)
650    }
651}