cairo_lang_semantic/expr/inference/
canonic.rs

1use cairo_lang_defs::ids::{
2    EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, GenericParamId, ImplAliasId, ImplDefId,
3    ImplFunctionId, ImplImplDefId, LocalVarId, MemberId, ParamId, StructId, TraitConstantId,
4    TraitFunctionId, TraitId, TraitImplId, TraitTypeId, VarId, VariantId,
5};
6use cairo_lang_proc_macros::SemanticObject;
7use cairo_lang_utils::Intern;
8use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
9use salsa::Database;
10
11use super::{
12    ConstVar, ImplVar, ImplVarId, ImplVarTraitItemMappings, Inference, InferenceId, InferenceVar,
13    LocalConstVarId, LocalImplVarId, LocalNegativeImplVarId, LocalTypeVarId, NegativeImplVar,
14    NegativeImplVarId, TypeVar,
15};
16use crate::items::constant::{ConstValue, ConstValueId, ImplConstantId};
17use crate::items::functions::{
18    ConcreteFunctionWithBody, ConcreteFunctionWithBodyId, GenericFunctionId,
19    GenericFunctionWithBodyId, ImplFunctionBodyId, ImplGenericFunctionId,
20    ImplGenericFunctionWithBodyId,
21};
22use crate::items::generics::{GenericParamConst, GenericParamImpl, GenericParamType};
23use crate::items::imp::{
24    GeneratedImplId, GeneratedImplItems, GeneratedImplLongId, ImplId, ImplImplId, ImplLongId,
25    NegativeImplId, NegativeImplLongId, UninferredGeneratedImplId, UninferredGeneratedImplLongId,
26    UninferredImpl,
27};
28use crate::items::trt::{
29    ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId, ConcreteTraitTypeId,
30    ConcreteTraitTypeLongId,
31};
32use crate::substitution::{HasDb, RewriteResult, SemanticObject, SemanticRewriter};
33use crate::types::{
34    ClosureTypeLongId, ConcreteEnumLongId, ConcreteExternTypeLongId, ConcreteStructLongId,
35    ImplTypeId,
36};
37use crate::{
38    ConcreteEnumId, ConcreteExternTypeId, ConcreteFunction, ConcreteImplId, ConcreteImplLongId,
39    ConcreteStructId, ConcreteTraitId, ConcreteTraitLongId, ConcreteTypeId, ConcreteVariant,
40    ExprId, ExprVar, ExprVarMemberPath, FunctionId, FunctionLongId, GenericArgumentId,
41    GenericParam, MatchArmSelector, Parameter, Signature, TypeId, TypeLongId, ValueSelectorArm,
42    add_basic_rewrites,
43};
44
45/// A canonical representation of a concrete trait that needs to be solved.
46#[derive(Clone, PartialEq, Hash, Eq, Debug, SemanticObject)]
47pub struct CanonicalTrait<'db> {
48    pub id: ConcreteTraitId<'db>,
49    pub mappings: ImplVarTraitItemMappings<'db>,
50}
51
52impl<'db> CanonicalTrait<'db> {
53    /// Canonicalizes a concrete trait that is part of an [Inference].
54    pub fn canonicalize(
55        db: &'db dyn Database,
56        source_inference_id: InferenceId<'db>,
57        trait_id: ConcreteTraitId<'db>,
58        impl_var_mappings: ImplVarTraitItemMappings<'db>,
59    ) -> (Self, CanonicalMapping<'db>) {
60        Canonicalizer::canonicalize(
61            db,
62            source_inference_id,
63            Self { id: trait_id, mappings: impl_var_mappings },
64        )
65    }
66    /// Embeds a canonical trait into an [Inference].
67    pub fn embed(
68        &self,
69        inference: &mut Inference<'db, '_>,
70    ) -> (CanonicalTrait<'db>, CanonicalMapping<'db>) {
71        Embedder::embed(inference, self.clone())
72    }
73}
74
75/// A solution for a [CanonicalTrait].
76#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, salsa::Update)]
77pub struct CanonicalImpl<'db>(pub ImplId<'db>);
78impl<'db> CanonicalImpl<'db> {
79    /// Canonicalizes a concrete impl that is part of an [Inference].
80    /// Uses the same canonicalization of the trait, to be consistent.
81    pub fn canonicalize(
82        db: &'db dyn Database,
83        impl_id: ImplId<'db>,
84        mapping: &CanonicalMapping<'db>,
85    ) -> Result<Self, MapperError> {
86        Ok(Self(Mapper::map(db, impl_id, &mapping.to_canonic)?))
87    }
88    /// Embeds a canonical impl into an [Inference].
89    /// Uses the same embedding of the trait, to be consistent.
90    pub fn embed(
91        &self,
92        inference: &Inference<'db, '_>,
93        mapping: &CanonicalMapping<'db>,
94    ) -> ImplId<'db> {
95        Mapper::map(inference.db, self.0, &mapping.from_canonic)
96            .expect("Tried to embed a non canonical impl")
97    }
98}
99
100/// Mapping between canonical space and inference space.
101/// Created by either canonicalizing or embedding a trait.
102#[derive(Debug)]
103pub struct CanonicalMapping<'db> {
104    to_canonic: VarMapping<'db>,
105    from_canonic: VarMapping<'db>,
106}
107impl<'db> CanonicalMapping<'db> {
108    fn from_to_canonic(to_canonic: VarMapping<'db>) -> CanonicalMapping<'db> {
109        let from_canonic = VarMapping {
110            type_var_mapping: to_canonic.type_var_mapping.iter().map(|(k, v)| (*v, *k)).collect(),
111            const_var_mapping: to_canonic.const_var_mapping.iter().map(|(k, v)| (*v, *k)).collect(),
112            impl_var_mapping: to_canonic.impl_var_mapping.iter().map(|(k, v)| (*v, *k)).collect(),
113            negative_impl_var_mapping: to_canonic
114                .negative_impl_var_mapping
115                .iter()
116                .map(|(k, v)| (*v, *k))
117                .collect(),
118            source_inference_id: to_canonic.target_inference_id,
119            target_inference_id: to_canonic.source_inference_id,
120        };
121        Self { to_canonic, from_canonic }
122    }
123    fn from_from_canonic(from_canonic: VarMapping<'db>) -> CanonicalMapping<'db> {
124        let to_canonic = VarMapping {
125            type_var_mapping: from_canonic.type_var_mapping.iter().map(|(k, v)| (*v, *k)).collect(),
126            const_var_mapping: from_canonic
127                .const_var_mapping
128                .iter()
129                .map(|(k, v)| (*v, *k))
130                .collect(),
131            impl_var_mapping: from_canonic.impl_var_mapping.iter().map(|(k, v)| (*v, *k)).collect(),
132            negative_impl_var_mapping: from_canonic
133                .negative_impl_var_mapping
134                .iter()
135                .map(|(k, v)| (*v, *k))
136                .collect(),
137            source_inference_id: from_canonic.target_inference_id,
138            target_inference_id: from_canonic.source_inference_id,
139        };
140        Self { to_canonic, from_canonic }
141    }
142}
143
144// Mappings.
145#[derive(Debug)]
146pub struct VarMapping<'db> {
147    type_var_mapping: OrderedHashMap<LocalTypeVarId, LocalTypeVarId>,
148    const_var_mapping: OrderedHashMap<LocalConstVarId, LocalConstVarId>,
149    impl_var_mapping: OrderedHashMap<LocalImplVarId, LocalImplVarId>,
150    negative_impl_var_mapping: OrderedHashMap<LocalNegativeImplVarId, LocalNegativeImplVarId>,
151    source_inference_id: InferenceId<'db>,
152    target_inference_id: InferenceId<'db>,
153}
154impl<'db> VarMapping<'db> {
155    fn new_to_canonic(source_inference_id: InferenceId<'db>) -> Self {
156        Self {
157            type_var_mapping: OrderedHashMap::default(),
158            const_var_mapping: OrderedHashMap::default(),
159            impl_var_mapping: OrderedHashMap::default(),
160            negative_impl_var_mapping: OrderedHashMap::default(),
161            source_inference_id,
162            target_inference_id: InferenceId::Canonical,
163        }
164    }
165    fn new_from_canonic(target_inference_id: InferenceId<'db>) -> Self {
166        Self {
167            type_var_mapping: OrderedHashMap::default(),
168            const_var_mapping: OrderedHashMap::default(),
169            impl_var_mapping: OrderedHashMap::default(),
170            negative_impl_var_mapping: OrderedHashMap::default(),
171            source_inference_id: InferenceId::Canonical,
172            target_inference_id,
173        }
174    }
175}
176
177/// A 'never' error.
178#[derive(Debug)]
179pub enum NoError {}
180pub trait ResultNoErrEx<T> {
181    fn no_err(self) -> T;
182}
183impl<T> ResultNoErrEx<T> for Result<T, NoError> {
184    fn no_err(self) -> T {
185        match self {
186            Ok(v) => v,
187            #[allow(unreachable_patterns)]
188            Err(err) => match err {},
189        }
190    }
191}
192
193/// Canonicalization rewriter. Each encountered variable is mapped to a new free variable,
194/// in pre-order.
195struct Canonicalizer<'db> {
196    db: &'db dyn Database,
197    to_canonic: VarMapping<'db>,
198}
199impl<'db> Canonicalizer<'db> {
200    fn canonicalize<T>(
201        db: &'db dyn Database,
202        source_inference_id: InferenceId<'db>,
203        value: T,
204    ) -> (T, CanonicalMapping<'db>)
205    where
206        Self: SemanticRewriter<T, NoError>,
207    {
208        let mut canonicalizer =
209            Self { db, to_canonic: VarMapping::new_to_canonic(source_inference_id) };
210        let value = canonicalizer.rewrite(value).no_err();
211        let mapping = CanonicalMapping::from_to_canonic(canonicalizer.to_canonic);
212        (value, mapping)
213    }
214}
215impl<'a> HasDb<&'a dyn Database> for Canonicalizer<'a> {
216    fn get_db(&self) -> &'a dyn Database {
217        self.db
218    }
219}
220
221add_basic_rewrites!(
222    <'a>,
223    Canonicalizer<'a>,
224    NoError,
225    @exclude TypeLongId TypeId ImplLongId ImplId ConstValue NegativeImplLongId NegativeImplId
226);
227
228impl<'db> SemanticRewriter<TypeId<'db>, NoError> for Canonicalizer<'db> {
229    fn internal_rewrite(&mut self, value: &mut TypeId<'db>) -> Result<RewriteResult, NoError> {
230        if value.is_var_free(self.db) {
231            return Ok(RewriteResult::NoChange);
232        }
233        value.default_rewrite(self)
234    }
235}
236impl<'db> SemanticRewriter<TypeLongId<'db>, NoError> for Canonicalizer<'db> {
237    fn internal_rewrite(&mut self, value: &mut TypeLongId<'db>) -> Result<RewriteResult, NoError> {
238        let TypeLongId::Var(var) = value else {
239            return value.default_rewrite(self);
240        };
241        if var.inference_id != self.to_canonic.source_inference_id {
242            return value.default_rewrite(self);
243        }
244        let next_id = LocalTypeVarId(self.to_canonic.type_var_mapping.len());
245        *value = TypeLongId::Var(TypeVar {
246            id: *self.to_canonic.type_var_mapping.entry(var.id).or_insert(next_id),
247            inference_id: InferenceId::Canonical,
248        });
249        Ok(RewriteResult::Modified)
250    }
251}
252impl<'db> SemanticRewriter<ConstValue<'db>, NoError> for Canonicalizer<'db> {
253    fn internal_rewrite(&mut self, value: &mut ConstValue<'db>) -> Result<RewriteResult, NoError> {
254        let ConstValue::Var(var, ty) = value else {
255            return value.default_rewrite(self);
256        };
257        if var.inference_id != self.to_canonic.source_inference_id {
258            return value.default_rewrite(self);
259        }
260        let next_id = LocalConstVarId(self.to_canonic.const_var_mapping.len());
261        ty.default_rewrite(self)?;
262        *value = ConstValue::Var(
263            ConstVar {
264                id: *self.to_canonic.const_var_mapping.entry(var.id).or_insert(next_id),
265                inference_id: InferenceId::Canonical,
266            },
267            *ty,
268        );
269        Ok(RewriteResult::Modified)
270    }
271}
272impl<'db> SemanticRewriter<ImplId<'db>, NoError> for Canonicalizer<'db> {
273    fn internal_rewrite(&mut self, value: &mut ImplId<'db>) -> Result<RewriteResult, NoError> {
274        if value.is_var_free(self.db) {
275            return Ok(RewriteResult::NoChange);
276        }
277        value.default_rewrite(self)
278    }
279}
280impl<'db> SemanticRewriter<ImplLongId<'db>, NoError> for Canonicalizer<'db> {
281    fn internal_rewrite(&mut self, value: &mut ImplLongId<'db>) -> Result<RewriteResult, NoError> {
282        let ImplLongId::ImplVar(var_id) = value else {
283            if value.is_var_free(self.db) {
284                return Ok(RewriteResult::NoChange);
285            }
286            return value.default_rewrite(self);
287        };
288        let var = var_id.long(self.db);
289        if var.inference_id != self.to_canonic.source_inference_id {
290            return value.default_rewrite(self);
291        }
292        let next_id = LocalImplVarId(self.to_canonic.impl_var_mapping.len());
293
294        let mut var = ImplVar {
295            id: *self.to_canonic.impl_var_mapping.entry(var.id).or_insert(next_id),
296            inference_id: InferenceId::Canonical,
297            lookup_context: var.lookup_context,
298            concrete_trait_id: var.concrete_trait_id,
299        };
300        var.concrete_trait_id.default_rewrite(self)?;
301        *value = ImplLongId::ImplVar(var.intern(self.db));
302        Ok(RewriteResult::Modified)
303    }
304}
305impl<'db> SemanticRewriter<NegativeImplId<'db>, NoError> for Canonicalizer<'db> {
306    fn internal_rewrite(
307        &mut self,
308        value: &mut NegativeImplId<'db>,
309    ) -> Result<RewriteResult, NoError> {
310        if value.is_var_free(self.db) {
311            return Ok(RewriteResult::NoChange);
312        }
313        value.default_rewrite(self)
314    }
315}
316impl<'db> SemanticRewriter<NegativeImplLongId<'db>, NoError> for Canonicalizer<'db> {
317    fn internal_rewrite(
318        &mut self,
319        value: &mut NegativeImplLongId<'db>,
320    ) -> Result<RewriteResult, NoError> {
321        let NegativeImplLongId::NegativeImplVar(var_id) = value else {
322            if value.is_var_free(self.db) {
323                return Ok(RewriteResult::NoChange);
324            }
325            return value.default_rewrite(self);
326        };
327        let var = var_id.long(self.db);
328        if var.inference_id != self.to_canonic.source_inference_id {
329            return value.default_rewrite(self);
330        }
331        let next_id = LocalNegativeImplVarId(self.to_canonic.negative_impl_var_mapping.len());
332
333        let mut var = NegativeImplVar {
334            id: *self.to_canonic.negative_impl_var_mapping.entry(var.id).or_insert(next_id),
335            inference_id: InferenceId::Canonical,
336            lookup_context: var.lookup_context,
337            concrete_trait_id: var.concrete_trait_id,
338        };
339        var.concrete_trait_id.default_rewrite(self)?;
340        *value = NegativeImplLongId::NegativeImplVar(var.intern(self.db));
341        Ok(RewriteResult::Modified)
342    }
343}
344
345/// Embedder rewriter. Each canonical variable is mapped to a new inference variable.
346struct Embedder<'db, 'id, 'mt> {
347    inference: &'mt mut Inference<'db, 'id>,
348    from_canonic: VarMapping<'db>,
349}
350impl<'db, 'id, 'mt> Embedder<'db, 'id, 'mt> {
351    fn embed<T>(inference: &'mt mut Inference<'db, 'id>, value: T) -> (T, CanonicalMapping<'db>)
352    where
353        Self: SemanticRewriter<T, NoError>,
354    {
355        let from_canonic = VarMapping::new_from_canonic(inference.inference_id);
356        let mut embedder = Self { inference, from_canonic };
357        let value = embedder.rewrite(value).no_err();
358        let mapping = CanonicalMapping::from_from_canonic(embedder.from_canonic);
359        (value, mapping)
360    }
361}
362
363impl<'db> HasDb<&'db dyn Database> for Embedder<'db, '_, '_> {
364    fn get_db(&self) -> &'db dyn Database {
365        self.inference.db
366    }
367}
368
369add_basic_rewrites!(
370    <'a, 'id, 'mt>,
371    Embedder<'a, 'id, 'mt>,
372    NoError,
373    @exclude TypeLongId TypeId ConstValue ImplLongId ImplId NegativeImplLongId NegativeImplId
374);
375
376impl<'db> SemanticRewriter<TypeId<'db>, NoError> for Embedder<'db, '_, '_> {
377    fn internal_rewrite(&mut self, value: &mut TypeId<'db>) -> Result<RewriteResult, NoError> {
378        if value.is_var_free(self.get_db()) {
379            return Ok(RewriteResult::NoChange);
380        }
381        value.default_rewrite(self)
382    }
383}
384impl<'db> SemanticRewriter<TypeLongId<'db>, NoError> for Embedder<'db, '_, '_> {
385    fn internal_rewrite(&mut self, value: &mut TypeLongId<'db>) -> Result<RewriteResult, NoError> {
386        let TypeLongId::Var(var) = value else {
387            return value.default_rewrite(self);
388        };
389        if var.inference_id != InferenceId::Canonical {
390            return value.default_rewrite(self);
391        }
392        let new_id = self
393            .from_canonic
394            .type_var_mapping
395            .entry(var.id)
396            .or_insert_with(|| self.inference.new_type_var_raw(None).id);
397        *value = TypeLongId::Var(self.inference.type_vars[new_id.0]);
398        Ok(RewriteResult::Modified)
399    }
400}
401impl<'db> SemanticRewriter<ConstValue<'db>, NoError> for Embedder<'db, '_, '_> {
402    fn internal_rewrite(&mut self, value: &mut ConstValue<'db>) -> Result<RewriteResult, NoError> {
403        let ConstValue::Var(var, ty) = value else {
404            return value.default_rewrite(self);
405        };
406        if var.inference_id != InferenceId::Canonical {
407            return value.default_rewrite(self);
408        }
409        ty.default_rewrite(self)?;
410        let new_id = self
411            .from_canonic
412            .const_var_mapping
413            .entry(var.id)
414            .or_insert_with(|| self.inference.new_const_var_raw(None).id);
415        *value = ConstValue::Var(self.inference.const_vars[new_id.0], *ty);
416        Ok(RewriteResult::Modified)
417    }
418}
419impl<'db> SemanticRewriter<ImplId<'db>, NoError> for Embedder<'db, '_, '_> {
420    fn internal_rewrite(&mut self, value: &mut ImplId<'db>) -> Result<RewriteResult, NoError> {
421        if value.is_var_free(self.get_db()) {
422            return Ok(RewriteResult::NoChange);
423        }
424        value.default_rewrite(self)
425    }
426}
427impl<'db> SemanticRewriter<ImplLongId<'db>, NoError> for Embedder<'db, '_, '_> {
428    fn internal_rewrite(&mut self, value: &mut ImplLongId<'db>) -> Result<RewriteResult, NoError> {
429        let ImplLongId::ImplVar(var_id) = value else {
430            if value.is_var_free(self.get_db()) {
431                return Ok(RewriteResult::NoChange);
432            }
433            return value.default_rewrite(self);
434        };
435        let var = var_id.long(self.get_db());
436        if var.inference_id != InferenceId::Canonical {
437            return value.default_rewrite(self);
438        }
439        let concrete_trait_id = self.rewrite(var.concrete_trait_id)?;
440        let new_id = self.from_canonic.impl_var_mapping.entry(var.id).or_insert_with(|| {
441            self.inference.new_impl_var_raw(var.lookup_context, concrete_trait_id, None)
442        });
443        *value =
444            ImplLongId::ImplVar(self.inference.impl_vars[new_id.0].clone().intern(self.get_db()));
445        Ok(RewriteResult::Modified)
446    }
447}
448impl<'db> SemanticRewriter<NegativeImplId<'db>, NoError> for Embedder<'db, '_, '_> {
449    fn internal_rewrite(
450        &mut self,
451        value: &mut NegativeImplId<'db>,
452    ) -> Result<RewriteResult, NoError> {
453        if value.is_var_free(self.get_db()) {
454            return Ok(RewriteResult::NoChange);
455        }
456        value.default_rewrite(self)
457    }
458}
459impl<'db> SemanticRewriter<NegativeImplLongId<'db>, NoError> for Embedder<'db, '_, '_> {
460    fn internal_rewrite(
461        &mut self,
462        value: &mut NegativeImplLongId<'db>,
463    ) -> Result<RewriteResult, NoError> {
464        let NegativeImplLongId::NegativeImplVar(var_id) = value else {
465            if value.is_var_free(self.get_db()) {
466                return Ok(RewriteResult::NoChange);
467            }
468            return value.default_rewrite(self);
469        };
470        let var = var_id.long(self.get_db());
471        if var.inference_id != InferenceId::Canonical {
472            return value.default_rewrite(self);
473        }
474        let concrete_trait_id = self.rewrite(var.concrete_trait_id)?;
475        let new_id =
476            self.from_canonic.negative_impl_var_mapping.entry(var.id).or_insert_with(|| {
477                self.inference.new_negative_impl_var_raw(
478                    var.lookup_context,
479                    concrete_trait_id,
480                    None,
481                )
482            });
483        *value = NegativeImplLongId::NegativeImplVar(
484            self.inference.negative_impl_vars[new_id.0].clone().intern(self.get_db()),
485        );
486        Ok(RewriteResult::Modified)
487    }
488}
489
490/// Mapper rewriter. Maps variables according to a given [VarMapping].
491#[derive(Clone, Debug)]
492pub struct MapperError(pub InferenceVar);
493struct Mapper<'db, 'v> {
494    db: &'db dyn Database,
495    mapping: &'v VarMapping<'db>,
496}
497impl<'db, 'v> Mapper<'db, 'v> {
498    fn map<T>(
499        db: &'db dyn Database,
500        value: T,
501        mapping: &'v VarMapping<'db>,
502    ) -> Result<T, MapperError>
503    where
504        Self: SemanticRewriter<T, MapperError>,
505    {
506        let mut mapper = Self { db, mapping };
507        mapper.rewrite(value)
508    }
509}
510
511impl<'db> HasDb<&'db dyn Database> for Mapper<'db, '_> {
512    fn get_db(&self) -> &'db dyn Database {
513        self.db
514    }
515}
516
517add_basic_rewrites!(
518    <'a>,
519    Mapper<'a, '_>,
520    MapperError,
521    @exclude TypeLongId TypeId ImplLongId ImplId ConstValue NegativeImplLongId NegativeImplId
522);
523
524impl<'db> SemanticRewriter<TypeId<'db>, MapperError> for Mapper<'db, '_> {
525    fn internal_rewrite(&mut self, value: &mut TypeId<'db>) -> Result<RewriteResult, MapperError> {
526        if value.is_var_free(self.db) {
527            return Ok(RewriteResult::NoChange);
528        }
529        value.default_rewrite(self)
530    }
531}
532impl<'db> SemanticRewriter<TypeLongId<'db>, MapperError> for Mapper<'db, '_> {
533    fn internal_rewrite(
534        &mut self,
535        value: &mut TypeLongId<'db>,
536    ) -> Result<RewriteResult, MapperError> {
537        let TypeLongId::Var(var) = value else {
538            return value.default_rewrite(self);
539        };
540        let id = self
541            .mapping
542            .type_var_mapping
543            .get(&var.id)
544            .copied()
545            .ok_or(MapperError(InferenceVar::Type(var.id)))?;
546        *value = TypeLongId::Var(TypeVar { id, inference_id: self.mapping.target_inference_id });
547        Ok(RewriteResult::Modified)
548    }
549}
550impl<'db> SemanticRewriter<ConstValue<'db>, MapperError> for Mapper<'db, '_> {
551    fn internal_rewrite(
552        &mut self,
553        value: &mut ConstValue<'db>,
554    ) -> Result<RewriteResult, MapperError> {
555        let ConstValue::Var(var, ty) = value else {
556            return value.default_rewrite(self);
557        };
558        let id = self
559            .mapping
560            .const_var_mapping
561            .get(&var.id)
562            .copied()
563            .ok_or(MapperError(InferenceVar::Const(var.id)))?;
564        ty.default_rewrite(self)?;
565        *value =
566            ConstValue::Var(ConstVar { id, inference_id: self.mapping.target_inference_id }, *ty);
567        Ok(RewriteResult::Modified)
568    }
569}
570impl<'db> SemanticRewriter<ImplId<'db>, MapperError> for Mapper<'db, '_> {
571    fn internal_rewrite(&mut self, value: &mut ImplId<'db>) -> Result<RewriteResult, MapperError> {
572        if value.is_var_free(self.db) {
573            return Ok(RewriteResult::NoChange);
574        }
575        value.default_rewrite(self)
576    }
577}
578impl<'db> SemanticRewriter<ImplLongId<'db>, MapperError> for Mapper<'db, '_> {
579    fn internal_rewrite(
580        &mut self,
581        value: &mut ImplLongId<'db>,
582    ) -> Result<RewriteResult, MapperError> {
583        let ImplLongId::ImplVar(var_id) = value else {
584            return value.default_rewrite(self);
585        };
586        let var = var_id.long(self.get_db());
587        let id = self
588            .mapping
589            .impl_var_mapping
590            .get(&var.id)
591            .copied()
592            .ok_or(MapperError(InferenceVar::Impl(var.id)))?;
593        let var = ImplVar { id, inference_id: self.mapping.target_inference_id, ..var.clone() };
594
595        *value = ImplLongId::ImplVar(var.intern(self.get_db()));
596        Ok(RewriteResult::Modified)
597    }
598}
599impl<'db> SemanticRewriter<NegativeImplId<'db>, MapperError> for Mapper<'db, '_> {
600    fn internal_rewrite(
601        &mut self,
602        value: &mut NegativeImplId<'db>,
603    ) -> Result<RewriteResult, MapperError> {
604        if value.is_var_free(self.db) {
605            return Ok(RewriteResult::NoChange);
606        }
607        value.default_rewrite(self)
608    }
609}
610impl<'db> SemanticRewriter<NegativeImplLongId<'db>, MapperError> for Mapper<'db, '_> {
611    fn internal_rewrite(
612        &mut self,
613        value: &mut NegativeImplLongId<'db>,
614    ) -> Result<RewriteResult, MapperError> {
615        let NegativeImplLongId::NegativeImplVar(var_id) = value else {
616            return value.default_rewrite(self);
617        };
618        let var = var_id.long(self.get_db());
619        let id = self
620            .mapping
621            .negative_impl_var_mapping
622            .get(&var.id)
623            .copied()
624            .ok_or(MapperError(InferenceVar::NegativeImpl(var.id)))?;
625        let var =
626            NegativeImplVar { id, inference_id: self.mapping.target_inference_id, ..var.clone() };
627
628        *value = NegativeImplLongId::NegativeImplVar(var.intern(self.get_db()));
629        Ok(RewriteResult::Modified)
630    }
631}