daml_lf/element/
daml_type.rs

1use std::borrow::Cow;
2
3use serde::Serialize;
4
5use crate::element::visitor::DamlElementVisitor;
6use crate::element::{DamlData, DamlField, DamlTypeVarWithKind, DamlVisitableElement};
7use bounded_static::ToStatic;
8use std::fmt;
9use std::fmt::{Display, Formatter};
10use std::hash::{Hash, Hasher};
11
12/// A Daml type.
13#[derive(Debug, Serialize, Clone, ToStatic)]
14pub enum DamlType<'a> {
15    /// Opaque contract identifier.
16    ContractId(Option<Box<DamlType<'a>>>),
17    /// Signed 64 bit integer.
18    Int64,
19    /// Fixed precision numeric.
20    Numeric(Vec<DamlType<'a>>),
21    /// Unicode text data.
22    Text,
23    /// A date & time.
24    Timestamp,
25    /// A Daml Party.
26    Party,
27    /// A Boolean type.
28    Bool,
29    /// A Unit type.
30    Unit,
31    /// A date.
32    Date,
33    /// A list.
34    List(Vec<DamlType<'a>>),
35    /// A map wih [DamlType::Text] keys.
36    TextMap(Vec<DamlType<'a>>),
37    /// A map.
38    GenMap(Vec<DamlType<'a>>),
39    /// An optional value.
40    Optional(Vec<DamlType<'a>>),
41    /// A type constructor.
42    TyCon(DamlTyCon<'a>),
43    /// A type constructor (heap allocated).
44    BoxedTyCon(DamlTyCon<'a>),
45    /// A type variable.
46    Var(DamlVar<'a>),
47    /// A natural number.
48    Nat(u8),
49    /// A function.
50    Arrow,
51    /// Any type.
52    Any,
53    /// A type rep.
54    TypeRep,
55    /// A big numeric.
56    Bignumeric,
57    /// A rounding mode.
58    RoundingMode,
59    /// An exception.
60    AnyException,
61    /// An update effect.
62    Update,
63    /// A scenario effect.
64    Scenario,
65    /// Universal qualifier.
66    Forall(DamlForall<'a>),
67    /// A struct type.
68    Struct(DamlStruct<'a>),
69    /// A type synonym.
70    Syn(DamlSyn<'a>),
71}
72
73impl<'a> DamlType<'a> {
74    pub fn name(&self) -> &str {
75        match self {
76            DamlType::ContractId(_) => "DamlContractId",
77            DamlType::Int64 => "DamlInt64",
78            DamlType::Numeric(_) => "DamlFixedNumeric",
79            DamlType::Text => "DamlText",
80            DamlType::Timestamp => "DamlTimestamp",
81            DamlType::Party => "DamlParty",
82            DamlType::Bool => "DamlBool",
83            DamlType::Unit => "DamlUnit",
84            DamlType::Date => "DamlDate",
85            DamlType::List(_) => "DamlList",
86            DamlType::TextMap(_) => "DamlTextMap",
87            DamlType::GenMap(_) => "DamlGenMap",
88            DamlType::Optional(_) => "DamlOptional",
89            DamlType::Update => "None (Update)",
90            DamlType::Scenario => "None (Scenario)",
91            DamlType::TyCon(_) => "None (TyCon)",
92            DamlType::BoxedTyCon(_) => "None (BoxedTyCon)",
93            DamlType::Var(_) => "None (Var)",
94            DamlType::Arrow => "None (Arrow)",
95            DamlType::Any => "None (Any)",
96            DamlType::TypeRep => "None (TypeRep)",
97            DamlType::RoundingMode => "None (RoundingMode)",
98            DamlType::AnyException => "None (AnyException)",
99            DamlType::Bignumeric => "None (Bignumeric)",
100            DamlType::Nat(_) => "Nat",
101            DamlType::Forall(_) => "Forall",
102            DamlType::Struct(_) => "Struct",
103            DamlType::Syn(_) => "Syn",
104        }
105    }
106
107    /// Returns true if this [`DamlType`] contain a reference to `type_var`, false otherwise.
108    pub fn contains_type_var(&self, type_var: &str) -> bool {
109        match self {
110            DamlType::Var(DamlVar {
111                var,
112                ..
113            }) => var == type_var,
114            DamlType::List(args)
115            | DamlType::Optional(args)
116            | DamlType::TextMap(args)
117            | DamlType::GenMap(args)
118            | DamlType::Numeric(args) => args.iter().any(|arg| arg.contains_type_var(type_var)),
119            DamlType::ContractId(inner) => inner.as_ref().map_or(false, |ty| ty.contains_type_var(type_var)),
120            DamlType::TyCon(tycon) | DamlType::BoxedTyCon(tycon) =>
121                tycon.type_arguments.iter().any(|f| f.contains_type_var(type_var)),
122            DamlType::Forall(forall) => forall.body.as_ref().contains_type_var(type_var),
123            DamlType::Struct(tuple) => tuple.fields.iter().any(|field| field.ty().contains_type_var(type_var)),
124            DamlType::Syn(syn) => syn.args.iter().any(|arg| arg.contains_type_var(type_var)),
125            DamlType::Int64
126            | DamlType::Text
127            | DamlType::Timestamp
128            | DamlType::Party
129            | DamlType::Bool
130            | DamlType::Unit
131            | DamlType::Date
132            | DamlType::Update
133            | DamlType::Scenario
134            | DamlType::Arrow
135            | DamlType::Any
136            | DamlType::TypeRep
137            | DamlType::Bignumeric
138            | DamlType::RoundingMode
139            | DamlType::AnyException
140            | DamlType::Nat(_) => false,
141        }
142    }
143
144    /// Convenience method to create a `DamlType::TyCon` for a given package id, module path and entity.
145    pub fn make_tycon<'b, S: AsRef<str> + 'b>(package_id: &'b str, module: &'b [S], entity: &'b str) -> DamlType<'b> {
146        Self::make_tycon_with_args(package_id, module, entity, vec![])
147    }
148
149    /// Convenience method to create a `DamlType::TyCon` for a given package id, module path, entity & type args.
150    pub fn make_tycon_with_args<'b, S: AsRef<str> + 'b>(
151        package_id: &'b str,
152        module: &'b [S],
153        entity: &'b str,
154        type_arguments: Vec<DamlType<'b>>,
155    ) -> DamlType<'b> {
156        DamlType::TyCon(DamlTyCon::new_absolute_with_type_args(package_id, module, entity, type_arguments))
157    }
158}
159
160impl<'a> DamlVisitableElement<'a> for DamlType<'a> {
161    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
162        visitor.pre_visit_type(self);
163        match self {
164            DamlType::Var(var) => var.accept(visitor),
165            DamlType::List(args)
166            | DamlType::Optional(args)
167            | DamlType::TextMap(args)
168            | DamlType::GenMap(args)
169            | DamlType::Numeric(args) => args.iter().for_each(|arg| arg.accept(visitor)),
170            DamlType::ContractId(tycon) => tycon.as_ref().map_or_else(|| {}, |dr| dr.accept(visitor)),
171            DamlType::TyCon(tycon) | DamlType::BoxedTyCon(tycon) => tycon.accept(visitor),
172            DamlType::Forall(forall) => forall.accept(visitor),
173            DamlType::Struct(tuple) => tuple.accept(visitor),
174            DamlType::Syn(syn) => syn.accept(visitor),
175            DamlType::Int64
176            | DamlType::Text
177            | DamlType::Timestamp
178            | DamlType::Party
179            | DamlType::Bool
180            | DamlType::Unit
181            | DamlType::Date
182            | DamlType::Update
183            | DamlType::Scenario
184            | DamlType::Arrow
185            | DamlType::Any
186            | DamlType::TypeRep
187            | DamlType::Bignumeric
188            | DamlType::RoundingMode
189            | DamlType::AnyException
190            | DamlType::Nat(_) => {},
191        }
192        visitor.post_visit_type(self);
193    }
194}
195
196/// `DamlTypeSynName` is aliases from `DamlTypeConName` as they are currently identical.
197pub type DamlTypeSynName<'a> = DamlTyConName<'a>;
198
199/// A Daml type synonym.
200#[derive(Debug, Serialize, Clone, ToStatic)]
201pub struct DamlSyn<'a> {
202    pub tysyn: Box<DamlTypeSynName<'a>>,
203    pub args: Vec<DamlType<'a>>,
204}
205
206impl<'a> DamlSyn<'a> {
207    pub fn new(tysyn: Box<DamlTypeSynName<'a>>, args: Vec<DamlType<'a>>) -> Self {
208        Self {
209            tysyn,
210            args,
211        }
212    }
213
214    pub fn tysyn(&self) -> &DamlTypeSynName<'a> {
215        &self.tysyn
216    }
217
218    pub fn args(&self) -> &[DamlType<'_>] {
219        &self.args
220    }
221}
222
223impl<'a> DamlVisitableElement<'a> for DamlSyn<'a> {
224    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
225        visitor.pre_visit_syn(self);
226        self.tysyn.accept(visitor);
227        self.args.iter().for_each(|field| field.accept(visitor));
228        visitor.post_visit_syn(self);
229    }
230}
231
232/// A Daml struct.
233#[derive(Debug, Serialize, Clone, ToStatic)]
234pub struct DamlStruct<'a> {
235    pub fields: Vec<DamlField<'a>>,
236}
237
238impl<'a> DamlStruct<'a> {
239    pub fn new(fields: Vec<DamlField<'a>>) -> Self {
240        Self {
241            fields,
242        }
243    }
244
245    pub fn fields(&self) -> &[DamlField<'_>] {
246        &self.fields
247    }
248}
249
250impl<'a> DamlVisitableElement<'a> for DamlStruct<'a> {
251    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
252        visitor.pre_visit_struct(self);
253        self.fields.iter().for_each(|field| field.accept(visitor));
254        visitor.post_visit_struct(self);
255    }
256}
257
258/// Universal qualifier.
259#[derive(Debug, Serialize, Clone, ToStatic)]
260pub struct DamlForall<'a> {
261    pub vars: Vec<DamlTypeVarWithKind<'a>>,
262    pub body: Box<DamlType<'a>>,
263}
264
265impl<'a> DamlForall<'a> {
266    pub fn new(vars: Vec<DamlTypeVarWithKind<'a>>, body: Box<DamlType<'a>>) -> Self {
267        Self {
268            vars,
269            body,
270        }
271    }
272
273    pub fn vars(&self) -> &[DamlTypeVarWithKind<'_>] {
274        &self.vars
275    }
276
277    pub fn body(&self) -> &DamlType<'a> {
278        &self.body
279    }
280}
281
282impl<'a> DamlVisitableElement<'a> for DamlForall<'a> {
283    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
284        visitor.pre_visit_forall(self);
285        self.vars.iter().for_each(|var| var.accept(visitor));
286        self.body.accept(visitor);
287        visitor.post_visit_forall(self);
288    }
289}
290
291/// A Daml type constructor.
292#[derive(Debug, Serialize, Clone, ToStatic)]
293pub struct DamlTyCon<'a> {
294    tycon: Box<DamlTyConName<'a>>,
295    type_arguments: Vec<DamlType<'a>>,
296}
297
298impl<'a> DamlTyCon<'a> {
299    pub fn new(tycon: Box<DamlTyConName<'a>>, type_arguments: Vec<DamlType<'a>>) -> Self {
300        Self {
301            tycon,
302            type_arguments,
303        }
304    }
305
306    pub fn new_absolute<'b, S: AsRef<str> + 'b>(
307        package_id: &'b str,
308        module: &'b [S],
309        entity: &'b str,
310    ) -> DamlTyCon<'b> {
311        Self::new_absolute_with_type_args(package_id, module, entity, vec![])
312    }
313
314    pub fn new_absolute_with_type_args<'b, S: AsRef<str> + 'b>(
315        package_id: &'b str,
316        module: &'b [S],
317        entity: &'b str,
318        type_arguments: Vec<DamlType<'b>>,
319    ) -> DamlTyCon<'b> {
320        DamlTyCon::new(Box::new(DamlTyConName::new_absolute(package_id, module, entity)), type_arguments)
321    }
322
323    pub fn type_arguments(&self) -> &[DamlType<'_>] {
324        &self.type_arguments
325    }
326
327    pub fn tycon(&self) -> &DamlTyConName<'_> {
328        &self.tycon
329    }
330}
331
332impl Hash for DamlTyCon<'_> {
333    fn hash<H: Hasher>(&self, state: &mut H) {
334        self.tycon.hash(state);
335    }
336}
337
338/// Equality for `DamlTyCon` is defined on the `DamlTyConName` only, `type_arguments` are not considered.
339impl PartialEq for DamlTyCon<'_> {
340    fn eq(&self, other: &Self) -> bool {
341        self.tycon == other.tycon
342    }
343}
344
345impl Eq for DamlTyCon<'_> {}
346
347impl<'a> DamlVisitableElement<'a> for DamlTyCon<'a> {
348    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
349        visitor.pre_visit_tycon(self);
350        self.tycon.accept(visitor);
351        self.type_arguments.iter().for_each(|arg| arg.accept(visitor));
352        visitor.post_visit_tycon(self);
353    }
354}
355
356/// A Daml type constructor.
357#[derive(Debug, Serialize, Clone, Hash, Eq, PartialEq, ToStatic)]
358pub enum DamlTyConName<'a> {
359    Local(DamlLocalTyCon<'a>),
360    NonLocal(DamlNonLocalTyCon<'a>),
361    Absolute(DamlAbsoluteTyCon<'a>),
362}
363
364impl<'a> DamlTyConName<'a> {
365    pub fn package_id(&self) -> &str {
366        match self {
367            DamlTyConName::Local(local) => &local.package_id,
368            DamlTyConName::NonLocal(non_local) => &non_local.target_package_id,
369            DamlTyConName::Absolute(abs) => &abs.package_id,
370        }
371    }
372
373    pub fn package_name(&self) -> &str {
374        match self {
375            DamlTyConName::Local(local) => &local.package_name,
376            DamlTyConName::NonLocal(non_local) => &non_local.target_package_name,
377            DamlTyConName::Absolute(abs) => &abs.package_name,
378        }
379    }
380
381    pub fn module_path(&self) -> impl Iterator<Item = &str> {
382        match self {
383            DamlTyConName::Local(local) => local.module_path.iter().map(AsRef::as_ref),
384            DamlTyConName::NonLocal(non_local) => non_local.target_module_path.iter().map(AsRef::as_ref),
385            DamlTyConName::Absolute(abs) => abs.module_path.iter().map(AsRef::as_ref),
386        }
387    }
388
389    pub fn data_name(&self) -> &str {
390        match self {
391            DamlTyConName::Local(local) => &local.data_name,
392            DamlTyConName::NonLocal(non_local) => &non_local.data_name,
393            DamlTyConName::Absolute(abs) => &abs.data_name,
394        }
395    }
396
397    pub fn new_absolute<'b, S: AsRef<str> + 'b>(
398        package_id: &'b str,
399        module: &'b [S],
400        entity: &'b str,
401    ) -> DamlTyConName<'b> {
402        DamlTyConName::Absolute(DamlAbsoluteTyCon::new(
403            entity.into(),
404            package_id.into(),
405            Cow::default(),
406            module.iter().map(AsRef::as_ref).map(Into::into).collect(),
407        ))
408    }
409
410    /// Extract the package id, module path and data name.
411    #[doc(hidden)]
412    pub(crate) fn reference_parts(&self) -> (&str, &[Cow<'_, str>], &str) {
413        match self {
414            DamlTyConName::Local(local) => (&local.package_id, &local.module_path, &local.data_name),
415            DamlTyConName::NonLocal(non_local) =>
416                (&non_local.target_package_id, &non_local.target_module_path, &non_local.data_name),
417            DamlTyConName::Absolute(abs) => (&abs.package_id, &abs.module_path, &abs.data_name),
418        }
419    }
420}
421
422impl Display for DamlTyConName<'_> {
423    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
424        match self {
425            DamlTyConName::Local(local) =>
426                write!(f, "{}:{}:{}", local.package_name, &local.module_path.join("."), local.data_name),
427            DamlTyConName::NonLocal(non_local) => write!(
428                f,
429                "{}:{}:{}",
430                non_local.target_package_name,
431                &non_local.target_module_path.join("."),
432                non_local.data_name
433            ),
434            DamlTyConName::Absolute(abs) =>
435                write!(f, "{}:{}:{}", abs.package_name, &abs.module_path.join("."), abs.data_name),
436        }
437    }
438}
439
440impl<'a> DamlVisitableElement<'a> for DamlTyConName<'a> {
441    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
442        visitor.pre_visit_tycon_name(self);
443        match self {
444            DamlTyConName::Local(local) => local.accept(visitor),
445            DamlTyConName::NonLocal(non_local) => non_local.accept(visitor),
446            DamlTyConName::Absolute(absolute) => absolute.accept(visitor),
447        }
448        visitor.post_visit_tycon_name(self);
449    }
450}
451
452/// Convenience impl to compare a `DamlData` with a `DamlTyConName`.
453impl PartialEq<DamlData<'_>> for DamlTyConName<'_> {
454    fn eq(&self, data: &DamlData<'_>) -> bool {
455        data == self
456    }
457}
458
459/// A Daml local type constructor.
460#[derive(Debug, Serialize, Clone, Hash, Eq, PartialEq, ToStatic)]
461pub struct DamlLocalTyCon<'a> {
462    data_name: Cow<'a, str>,
463    package_id: Cow<'a, str>,
464    package_name: Cow<'a, str>,
465    module_path: Vec<Cow<'a, str>>,
466}
467
468impl<'a> DamlLocalTyCon<'a> {
469    pub fn new(
470        data_name: Cow<'a, str>,
471        package_id: Cow<'a, str>,
472        package_name: Cow<'a, str>,
473        module_path: Vec<Cow<'a, str>>,
474    ) -> Self {
475        Self {
476            data_name,
477            package_id,
478            package_name,
479            module_path,
480        }
481    }
482
483    pub fn data_name(&self) -> &str {
484        &self.data_name
485    }
486
487    pub fn package_id(&self) -> &str {
488        &self.package_id
489    }
490
491    pub fn package_name(&self) -> &str {
492        &self.package_name
493    }
494
495    pub fn module_path(&self) -> impl Iterator<Item = &str> {
496        self.module_path.iter().map(AsRef::as_ref)
497    }
498}
499
500impl<'a> DamlVisitableElement<'a> for DamlLocalTyCon<'a> {
501    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
502        visitor.pre_visit_local_tycon(self);
503        visitor.post_visit_local_tycon(self);
504    }
505}
506
507/// A Daml non-local type constructor.
508#[derive(Debug, Serialize, Clone, Hash, Eq, PartialEq, ToStatic)]
509pub struct DamlNonLocalTyCon<'a> {
510    data_name: Cow<'a, str>,
511    source_package_id: Cow<'a, str>,
512    source_package_name: Cow<'a, str>,
513    source_module_path: Vec<Cow<'a, str>>,
514    target_package_id: Cow<'a, str>,
515    target_package_name: Cow<'a, str>,
516    target_module_path: Vec<Cow<'a, str>>,
517}
518
519impl<'a> DamlNonLocalTyCon<'a> {
520    pub fn new(
521        data_name: Cow<'a, str>,
522        source_package_id: Cow<'a, str>,
523        source_package_name: Cow<'a, str>,
524        source_module_path: Vec<Cow<'a, str>>,
525        target_package_id: Cow<'a, str>,
526        target_package_name: Cow<'a, str>,
527        target_module_path: Vec<Cow<'a, str>>,
528    ) -> Self {
529        Self {
530            data_name,
531            source_package_id,
532            source_package_name,
533            source_module_path,
534            target_package_id,
535            target_package_name,
536            target_module_path,
537        }
538    }
539
540    pub fn data_name(&self) -> &str {
541        &self.data_name
542    }
543
544    pub fn source_package_id(&self) -> &str {
545        &self.source_package_id
546    }
547
548    pub fn source_package_name(&self) -> &str {
549        &self.source_package_name
550    }
551
552    pub fn source_module_path(&self) -> impl Iterator<Item = &str> {
553        self.source_module_path.iter().map(AsRef::as_ref)
554    }
555
556    pub fn target_package_id(&self) -> &str {
557        &self.target_package_id
558    }
559
560    pub fn target_package_name(&self) -> &str {
561        &self.target_package_name
562    }
563
564    pub fn target_module_path(&self) -> impl Iterator<Item = &str> {
565        self.target_module_path.iter().map(AsRef::as_ref)
566    }
567}
568
569impl<'a> DamlVisitableElement<'a> for DamlNonLocalTyCon<'a> {
570    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
571        visitor.pre_visit_non_local_tycon(self);
572        visitor.post_visit_non_local_tycon(self);
573    }
574}
575
576/// A Daml absolute type constructor.
577#[derive(Debug, Serialize, Clone, Hash, Eq, PartialEq, ToStatic)]
578pub struct DamlAbsoluteTyCon<'a> {
579    data_name: Cow<'a, str>,
580    package_id: Cow<'a, str>,
581    package_name: Cow<'a, str>,
582    module_path: Vec<Cow<'a, str>>,
583}
584
585impl<'a> DamlAbsoluteTyCon<'a> {
586    pub fn new(
587        data_name: Cow<'a, str>,
588        package_id: Cow<'a, str>,
589        package_name: Cow<'a, str>,
590        module_path: Vec<Cow<'a, str>>,
591    ) -> Self {
592        Self {
593            data_name,
594            package_id,
595            package_name,
596            module_path,
597        }
598    }
599
600    pub fn data_name(&self) -> &str {
601        &self.data_name
602    }
603
604    pub fn package_id(&self) -> &str {
605        &self.package_id
606    }
607
608    pub fn package_name(&self) -> &str {
609        &self.package_name
610    }
611
612    pub fn module_path(&self) -> impl Iterator<Item = &str> {
613        self.module_path.iter().map(AsRef::as_ref)
614    }
615}
616
617impl<'a> DamlVisitableElement<'a> for DamlAbsoluteTyCon<'a> {
618    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
619        visitor.pre_visit_absolute_tycon(self);
620        visitor.post_visit_absolute_tycon(self);
621    }
622}
623
624/// A Daml type variable.
625#[derive(Debug, Serialize, Clone, ToStatic)]
626pub struct DamlVar<'a> {
627    var: Cow<'a, str>,
628    type_arguments: Vec<DamlType<'a>>,
629}
630
631impl<'a> DamlVar<'a> {
632    pub fn new(var: Cow<'a, str>, type_arguments: Vec<DamlType<'a>>) -> Self {
633        Self {
634            var,
635            type_arguments,
636        }
637    }
638
639    pub fn var(&self) -> &str {
640        &self.var
641    }
642
643    pub fn type_arguments(&self) -> &[DamlType<'a>] {
644        &self.type_arguments
645    }
646}
647
648impl<'a> DamlVisitableElement<'a> for DamlVar<'a> {
649    fn accept(&'a self, visitor: &'a mut impl DamlElementVisitor) {
650        visitor.pre_visit_var(self);
651        self.type_arguments.iter().for_each(|arg| arg.accept(visitor));
652        visitor.post_visit_var(self);
653    }
654}