cairo_lang_semantic/
substitution.rs

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