goscript_types/
typ.rs

1#![allow(dead_code)]
2use super::obj::{LangObj, ObjSet};
3use super::objects::{ObjKey, ScopeKey, TCObjects, TypeKey};
4use std::cell::{Ref, RefCell, RefMut};
5use std::collections::HashSet;
6use std::fmt;
7use std::fmt::Debug;
8use std::fmt::Write;
9use std::mem::size_of as std_size_of;
10use std::rc::Rc;
11
12macro_rules! compare_by_method_name {
13    ($objs:expr) => {{
14        |a, b| {
15            let oa = &$objs.lobjs[*a];
16            let ob = &$objs.lobjs[*b];
17            oa.id($objs).as_ref().cmp(ob.id($objs).as_ref())
18        }
19    }};
20}
21
22macro_rules! compare_by_type_name {
23    ($objs:expr) => {{
24        |a, b| {
25            let sort_name = |t: &Type| match t {
26                Type::Named(n) => {
27                    let typ = &$objs.lobjs[n.obj().unwrap()];
28                    typ.id($objs)
29                }
30                _ => "".into(),
31            };
32            let ta = sort_name(&$objs.types[*a]);
33            let tb = sort_name(&$objs.types[*b]);
34            ta.as_ref().cmp(tb.as_ref())
35        }
36    }};
37}
38
39#[derive(Debug)]
40pub enum Type {
41    Basic(BasicDetail),
42    Array(ArrayDetail),
43    Slice(SliceDetail),
44    Struct(StructDetail),
45    Pointer(PointerDetail),
46    Tuple(TupleDetail),
47    Signature(SignatureDetail),
48    Interface(InterfaceDetail),
49    Map(MapDetail),
50    Chan(ChanDetail),
51    Named(NamedDetail),
52}
53
54impl Type {
55    pub fn try_as_basic(&self) -> Option<&BasicDetail> {
56        match &self {
57            Type::Basic(b) => Some(b),
58            _ => None,
59        }
60    }
61
62    pub fn try_as_array(&self) -> Option<&ArrayDetail> {
63        match &self {
64            Type::Array(a) => Some(a),
65            _ => None,
66        }
67    }
68
69    pub fn try_as_array_mut(&mut self) -> Option<&mut ArrayDetail> {
70        match self {
71            Type::Array(a) => Some(a),
72            _ => None,
73        }
74    }
75
76    pub fn try_as_slice(&self) -> Option<&SliceDetail> {
77        match &self {
78            Type::Slice(s) => Some(s),
79            _ => None,
80        }
81    }
82
83    pub fn try_as_struct(&self) -> Option<&StructDetail> {
84        match &self {
85            Type::Struct(s) => Some(s),
86            _ => None,
87        }
88    }
89
90    pub fn try_as_pointer(&self) -> Option<&PointerDetail> {
91        match &self {
92            Type::Pointer(p) => Some(p),
93            _ => None,
94        }
95    }
96
97    pub fn try_as_tuple(&self) -> Option<&TupleDetail> {
98        match self {
99            Type::Tuple(t) => Some(t),
100            _ => None,
101        }
102    }
103
104    pub fn try_as_tuple_mut(&mut self) -> Option<&mut TupleDetail> {
105        match self {
106            Type::Tuple(t) => Some(t),
107            _ => None,
108        }
109    }
110
111    pub fn try_as_signature(&self) -> Option<&SignatureDetail> {
112        match self {
113            Type::Signature(s) => Some(s),
114            _ => None,
115        }
116    }
117
118    pub fn try_as_signature_mut(&mut self) -> Option<&mut SignatureDetail> {
119        match self {
120            Type::Signature(s) => Some(s),
121            _ => None,
122        }
123    }
124
125    pub fn try_as_interface(&self) -> Option<&InterfaceDetail> {
126        match &self {
127            Type::Interface(i) => Some(i),
128            _ => None,
129        }
130    }
131
132    pub fn try_as_interface_mut(&mut self) -> Option<&mut InterfaceDetail> {
133        match self {
134            Type::Interface(i) => Some(i),
135            _ => None,
136        }
137    }
138
139    pub fn try_as_map(&self) -> Option<&MapDetail> {
140        match &self {
141            Type::Map(m) => Some(m),
142            _ => None,
143        }
144    }
145
146    pub fn try_as_chan(&self) -> Option<&ChanDetail> {
147        match self {
148            Type::Chan(c) => Some(c),
149            _ => None,
150        }
151    }
152
153    pub fn try_as_chan_mut(&mut self) -> Option<&mut ChanDetail> {
154        match self {
155            Type::Chan(c) => Some(c),
156            _ => None,
157        }
158    }
159
160    pub fn try_as_named(&self) -> Option<&NamedDetail> {
161        match self {
162            Type::Named(n) => Some(n),
163            _ => None,
164        }
165    }
166
167    pub fn try_as_named_mut(&mut self) -> Option<&mut NamedDetail> {
168        match self {
169            Type::Named(n) => Some(n),
170            _ => None,
171        }
172    }
173
174    pub fn underlying(&self) -> Option<TypeKey> {
175        match self {
176            Type::Named(detail) => detail.underlying,
177            _ => None,
178        }
179    }
180
181    pub fn underlying_val<'a>(&'a self, objs: &'a TCObjects) -> &'a Type {
182        if let Some(k) = self.underlying() {
183            &objs.types[k]
184        } else {
185            &self
186        }
187    }
188
189    pub fn is_named(&self) -> bool {
190        match self {
191            Type::Basic(_) | Type::Named(_) => true,
192            _ => false,
193        }
194    }
195    pub fn is_invalid(&self, objs: &TCObjects) -> bool {
196        match self.underlying_val(objs) {
197            Type::Basic(b) => b.info() == BasicInfo::IsInvalid,
198            _ => false,
199        }
200    }
201    pub fn is_boolean(&self, objs: &TCObjects) -> bool {
202        match self.underlying_val(objs) {
203            Type::Basic(b) => b.info() == BasicInfo::IsBoolean,
204            _ => false,
205        }
206    }
207    pub fn is_integer(&self, objs: &TCObjects) -> bool {
208        match self.underlying_val(objs) {
209            Type::Basic(b) => b.info() == BasicInfo::IsInteger,
210            _ => false,
211        }
212    }
213    pub fn is_unsigned(&self, objs: &TCObjects) -> bool {
214        match self.underlying_val(objs) {
215            Type::Basic(b) => b.typ().is_unsigned(),
216            _ => false,
217        }
218    }
219    pub fn is_float(&self, objs: &TCObjects) -> bool {
220        match self.underlying_val(objs) {
221            Type::Basic(b) => b.info() == BasicInfo::IsFloat,
222            _ => false,
223        }
224    }
225    pub fn is_complex(&self, objs: &TCObjects) -> bool {
226        match self.underlying_val(objs) {
227            Type::Basic(b) => b.info() == BasicInfo::IsComplex,
228            _ => false,
229        }
230    }
231    pub fn is_numeric(&self, objs: &TCObjects) -> bool {
232        match self.underlying_val(objs) {
233            Type::Basic(b) => b.info().is_numeric(),
234            _ => false,
235        }
236    }
237    pub fn is_string(&self, objs: &TCObjects) -> bool {
238        match self.underlying_val(objs) {
239            Type::Basic(b) => b.info() == BasicInfo::IsString,
240            _ => false,
241        }
242    }
243    pub fn is_typed(&self, objs: &TCObjects) -> bool {
244        match self.underlying_val(objs) {
245            Type::Basic(b) => !b.typ().is_untyped(),
246            _ => true,
247        }
248    }
249    pub fn is_untyped(&self, objs: &TCObjects) -> bool {
250        match self.underlying_val(objs) {
251            Type::Basic(b) => b.typ().is_untyped(),
252            _ => false,
253        }
254    }
255    pub fn is_ordered(&self, objs: &TCObjects) -> bool {
256        match self.underlying_val(objs) {
257            Type::Basic(b) => b.info().is_ordered(),
258            _ => false,
259        }
260    }
261    pub fn is_const_type(&self, objs: &TCObjects) -> bool {
262        match self.underlying_val(objs) {
263            Type::Basic(b) => b.info().is_const_type(),
264            _ => false,
265        }
266    }
267    pub fn is_interface(&self, objs: &TCObjects) -> bool {
268        match self.underlying_val(objs) {
269            Type::Interface(_) => true,
270            _ => false,
271        }
272    }
273    /// has_nil reports whether a type includes the nil value.
274    pub fn has_nil(&self, objs: &TCObjects) -> bool {
275        match self.underlying_val(objs) {
276            Type::Basic(b) => b.typ() == BasicType::UnsafePointer,
277            Type::Slice(_)
278            | Type::Pointer(_)
279            | Type::Signature(_)
280            | Type::Interface(_)
281            | Type::Map(_)
282            | Type::Chan(_) => true,
283            _ => false,
284        }
285    }
286    /// comparable reports whether values of type T are comparable.
287    pub fn comparable(&self, objs: &TCObjects) -> bool {
288        match self.underlying_val(objs) {
289            Type::Basic(b) => b.typ() != BasicType::UntypedNil,
290            Type::Pointer(_) | Type::Interface(_) | Type::Chan(_) => true,
291            Type::Struct(s) => !s
292                .fields()
293                .iter()
294                .any(|f| !comparable(objs.lobjs[*f].typ().unwrap(), objs)),
295            Type::Array(a) => comparable(a.elem(), objs),
296            _ => false,
297        }
298    }
299}
300
301#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
302pub enum BasicType {
303    Invalid,
304    // predeclared types
305    Bool,
306    Int,
307    Int8,
308    Int16,
309    Int32,
310    Int64,
311    Uint,
312    Uint8,
313    Uint16,
314    Uint32,
315    Uint64,
316    Uintptr,
317    Float32,
318    Float64,
319    Complex64,
320    Complex128,
321    Str,
322    UnsafePointer,
323    // types for untyped values
324    UntypedBool,
325    UntypedInt,
326    UntypedRune,
327    UntypedFloat,
328    UntypedComplex,
329    UntypedString,
330    UntypedNil,
331    // aliases
332    Byte, // = Uint8
333    Rune, // = Int32
334}
335
336impl BasicType {
337    pub fn is_unsigned(&self) -> bool {
338        match self {
339            BasicType::Uint
340            | BasicType::Uint8
341            | BasicType::Uint16
342            | BasicType::Uint32
343            | BasicType::Uint64
344            | BasicType::Byte
345            | BasicType::Rune
346            | BasicType::Uintptr => true,
347            _ => false,
348        }
349    }
350
351    pub fn is_untyped(&self) -> bool {
352        match self {
353            BasicType::UntypedBool
354            | BasicType::UntypedInt
355            | BasicType::UntypedRune
356            | BasicType::UntypedFloat
357            | BasicType::UntypedComplex
358            | BasicType::UntypedString
359            | BasicType::UntypedNil => true,
360            _ => false,
361        }
362    }
363
364    pub fn real_type(&self) -> BasicType {
365        match self {
366            BasicType::Byte => BasicType::Uint8,
367            BasicType::Rune => BasicType::Int32,
368            _ => *self,
369        }
370    }
371}
372
373#[derive(Copy, Clone, Debug, PartialEq, Eq)]
374pub enum BasicInfo {
375    IsInvalid,
376    IsBoolean,
377    IsInteger,
378    IsFloat,
379    IsComplex,
380    IsString,
381}
382
383impl BasicInfo {
384    pub fn is_ordered(&self) -> bool {
385        match self {
386            BasicInfo::IsInteger | BasicInfo::IsFloat | BasicInfo::IsString => true,
387            _ => false,
388        }
389    }
390
391    pub fn is_numeric(&self) -> bool {
392        match self {
393            BasicInfo::IsInteger | BasicInfo::IsFloat | BasicInfo::IsComplex => true,
394            _ => false,
395        }
396    }
397
398    pub fn is_const_type(&self) -> bool {
399        match self {
400            BasicInfo::IsBoolean
401            | BasicInfo::IsInteger
402            | BasicInfo::IsFloat
403            | BasicInfo::IsComplex
404            | BasicInfo::IsString => true,
405            _ => false,
406        }
407    }
408}
409
410/// A BasicDetail represents a basic type.
411#[derive(Copy, Clone, Debug)]
412pub struct BasicDetail {
413    typ: BasicType,
414    info: BasicInfo,
415    name: &'static str,
416}
417
418impl BasicDetail {
419    pub fn new(typ: BasicType, info: BasicInfo, name: &'static str) -> BasicDetail {
420        BasicDetail {
421            typ: typ,
422            info: info,
423            name: name,
424        }
425    }
426
427    pub fn typ(&self) -> BasicType {
428        self.typ
429    }
430
431    pub fn info(&self) -> BasicInfo {
432        self.info
433    }
434
435    pub fn name(&self) -> &str {
436        self.name
437    }
438
439    pub fn size_of(&self) -> usize {
440        match self.typ {
441            BasicType::Bool | BasicType::Byte | BasicType::Uint8 | BasicType::Int8 => 1,
442            BasicType::Int16 | BasicType::Uint16 => 2,
443            BasicType::Int32 | BasicType::Uint32 | BasicType::Rune | BasicType::Float32 => 4,
444            BasicType::Int64 | BasicType::Uint64 | BasicType::Float64 | BasicType::Complex64 => 8,
445            BasicType::Int | BasicType::Uint | BasicType::Uintptr | BasicType::UnsafePointer => {
446                std_size_of::<usize>()
447            }
448            BasicType::Complex128 => 16,
449            BasicType::Str => std_size_of::<String>(),
450            _ => unreachable!(),
451        }
452    }
453}
454
455/// An ArrayDetail represents an array type.
456#[derive(Debug)]
457pub struct ArrayDetail {
458    len: Option<u64>,
459    elem: TypeKey,
460}
461
462impl ArrayDetail {
463    pub fn new(elem: TypeKey, len: Option<u64>) -> ArrayDetail {
464        ArrayDetail {
465            len: len,
466            elem: elem,
467        }
468    }
469
470    pub fn len(&self) -> Option<u64> {
471        self.len
472    }
473
474    pub fn set_len(&mut self, len: u64) {
475        self.len = Some(len);
476    }
477
478    pub fn elem(&self) -> TypeKey {
479        self.elem
480    }
481}
482
483/// A Slice represents a slice type.
484#[derive(Debug)]
485pub struct SliceDetail {
486    elem: TypeKey,
487}
488
489impl SliceDetail {
490    pub fn new(elem: TypeKey) -> SliceDetail {
491        SliceDetail { elem: elem }
492    }
493
494    pub fn elem(&self) -> TypeKey {
495        self.elem
496    }
497}
498
499/// A StructDetail represents a struct type
500#[derive(Debug)]
501pub struct StructDetail {
502    fields: Vec<ObjKey>,               // objects of type LangObj::Var
503    tags: Option<Vec<Option<String>>>, // None if there are no tags
504}
505
506impl StructDetail {
507    pub fn new(
508        fields: Vec<ObjKey>,
509        tags: Option<Vec<Option<String>>>,
510        objs: &TCObjects,
511    ) -> StructDetail {
512        // sanity checks
513        if cfg!(debug_assertions) {
514            let set = ObjSet::new();
515            let result = fields.iter().try_fold(set, |s, x| {
516                if !objs.lobjs[*x].entity_type().is_var() {
517                    Err(())
518                } else if s.insert(*x, objs).is_some() {
519                    Err(())
520                } else {
521                    Ok::<ObjSet, ()>(s)
522                }
523            });
524            assert!(result.is_ok());
525            assert!(tags.is_none() || fields.len() >= tags.as_ref().unwrap().len());
526        }
527        StructDetail {
528            fields: fields,
529            tags: tags,
530        }
531    }
532
533    pub fn fields(&self) -> &Vec<ObjKey> {
534        &self.fields
535    }
536
537    pub fn tag(&self, i: usize) -> Option<&String> {
538        self.tags
539            .as_ref()
540            .map(|x| if i < x.len() { x[i].as_ref() } else { None })
541            .flatten()
542    }
543}
544
545/// A PointerDetail represents a pointer type.
546#[derive(Debug)]
547pub struct PointerDetail {
548    base: TypeKey, // element type
549}
550
551impl PointerDetail {
552    pub fn new(base: TypeKey) -> PointerDetail {
553        PointerDetail { base: base }
554    }
555
556    pub fn base(&self) -> TypeKey {
557        self.base
558    }
559}
560
561/// A TupleDetail represents an ordered list of variables
562/// Tuples are used as components of signatures and to represent the type of multiple
563/// assignments; they are not first class types of Go.
564#[derive(Debug)]
565pub struct TupleDetail {
566    vars: Vec<ObjKey>, // LangObj::Var
567}
568
569impl TupleDetail {
570    pub fn new(vars: Vec<ObjKey>) -> TupleDetail {
571        TupleDetail { vars: vars }
572    }
573
574    pub fn vars(&self) -> &Vec<ObjKey> {
575        &self.vars
576    }
577
578    pub fn vars_mut(&mut self) -> &mut Vec<ObjKey> {
579        &mut self.vars
580    }
581}
582
583/// A SignatureDetail represents a (non-builtin) function or method type.
584/// The receiver is ignored when comparing signatures for identity.
585#[derive(Copy, Clone, Debug)]
586pub struct SignatureDetail {
587    scope: Option<ScopeKey>, // function scope, present for package-local signatures
588    recv: Option<ObjKey>,    // None if not a method
589    params: TypeKey,
590    results: TypeKey,
591    variadic: bool,
592}
593
594impl SignatureDetail {
595    pub fn new(
596        scope: Option<ScopeKey>,
597        recv: Option<ObjKey>,
598        params: TypeKey,
599        results: TypeKey,
600        variadic: bool,
601        objs: &TCObjects,
602    ) -> SignatureDetail {
603        // doesn't apply to append(s, str...), disabled
604        if false && cfg!(debug_assertions) {
605            if variadic {
606                let typ = &objs.types[params];
607                match typ {
608                    Type::Tuple(t) => {
609                        assert!(t.vars.len() > 0);
610                        let okey = t.vars[t.vars.len() - 1];
611                        let tkey = &objs.lobjs[okey].typ().unwrap();
612                        assert!(objs.types[*tkey].try_as_slice().is_some());
613                    }
614                    _ => unreachable!(),
615                }
616            }
617        }
618        SignatureDetail {
619            scope: scope,
620            recv: recv,
621            params: params,
622            results: results,
623            variadic: variadic,
624        }
625    }
626
627    pub fn scope(&self) -> Option<ScopeKey> {
628        self.scope
629    }
630
631    /// Recv returns the receiver of signature s (if a method), or nil if a
632    /// function. It is ignored when comparing signatures for identity.
633    ///
634    /// For an abstract method, Recv returns the enclosing interface either
635    /// as a *Named or an *Interface. Due to embedding, an interface may
636    /// contain methods whose receiver type is a different interface.
637    pub fn recv(&self) -> &Option<ObjKey> {
638        &self.recv
639    }
640
641    pub fn set_recv(&mut self, r: Option<ObjKey>) {
642        self.recv = r
643    }
644
645    pub fn params(&self) -> TypeKey {
646        self.params
647    }
648
649    pub fn set_params(&mut self, p: TypeKey) {
650        self.params = p;
651    }
652
653    pub fn results(&self) -> TypeKey {
654        self.results
655    }
656
657    pub fn variadic(&self) -> bool {
658        self.variadic
659    }
660
661    pub fn params_count(&self, objs: &TCObjects) -> usize {
662        let l = objs.types[self.params].try_as_tuple().unwrap().vars().len();
663        if self.variadic {
664            l - 1
665        } else {
666            l
667        }
668    }
669
670    pub fn results_count(&self, objs: &TCObjects) -> usize {
671        objs.types[self.results]
672            .try_as_tuple()
673            .unwrap()
674            .vars()
675            .len()
676    }
677}
678
679/// An InterfaceDetail represents an interface type.
680#[derive(Debug)]
681pub struct InterfaceDetail {
682    methods: Vec<ObjKey>,
683    embeddeds: Vec<TypeKey>,
684    all_methods: Rc<RefCell<Option<Vec<ObjKey>>>>,
685}
686
687impl InterfaceDetail {
688    pub fn new(
689        mut methods: Vec<ObjKey>,
690        mut embeddeds: Vec<TypeKey>,
691        objs: &mut TCObjects,
692    ) -> InterfaceDetail {
693        let set = ObjSet::new();
694        let result = methods.iter().try_fold(set, |s, x| {
695            let mobj = &objs.lobjs[*x];
696            if !mobj.entity_type().is_func() {
697                Err(())
698            } else if s.insert(*x, &objs).is_some() {
699                Err(())
700            } else {
701                let signature = objs.types[mobj.typ().unwrap()].try_as_signature_mut();
702                if let Some(sig) = signature {
703                    if sig.recv.is_none() {
704                        let var =
705                            LangObj::new_var(mobj.pos(), mobj.pkg(), "".to_string(), mobj.typ());
706                        sig.recv = Some(objs.lobjs.insert(var));
707                    }
708                    Ok(s)
709                } else {
710                    Err(())
711                }
712            }
713        });
714        assert!(result.is_ok());
715        methods.sort_by(compare_by_method_name!(&objs));
716        embeddeds.sort_by(compare_by_type_name!(&objs));
717        InterfaceDetail {
718            methods: methods,
719            embeddeds: embeddeds,
720            all_methods: Rc::new(RefCell::new(None)),
721        }
722    }
723
724    pub fn new_empty() -> InterfaceDetail {
725        InterfaceDetail {
726            methods: Vec::new(),
727            embeddeds: Vec::new(),
728            all_methods: Rc::new(RefCell::new(Some(Vec::new()))),
729        }
730    }
731
732    pub fn methods(&self) -> &Vec<ObjKey> {
733        &self.methods
734    }
735
736    pub fn methods_mut(&mut self) -> &mut Vec<ObjKey> {
737        &mut self.methods
738    }
739
740    pub fn embeddeds(&self) -> &Vec<TypeKey> {
741        &self.embeddeds
742    }
743
744    pub fn embeddeds_mut(&mut self) -> &mut Vec<TypeKey> {
745        &mut self.embeddeds
746    }
747
748    pub fn all_methods(&self) -> Ref<Option<Vec<ObjKey>>> {
749        self.all_methods.borrow()
750    }
751
752    pub fn all_methods_mut(&self) -> RefMut<Option<Vec<ObjKey>>> {
753        self.all_methods.borrow_mut()
754    }
755
756    pub fn all_methods_push(&self, t: ObjKey) {
757        if self.all_methods.borrow_mut().is_none() {
758            *self.all_methods.borrow_mut() = Some(vec![t]);
759        } else {
760            self.all_methods.borrow_mut().as_mut().unwrap().push(t);
761        }
762    }
763
764    pub fn is_empty(&self) -> bool {
765        self.all_methods().as_ref().unwrap().len() == 0
766    }
767
768    pub fn set_empty_complete(&self) {
769        *self.all_methods.borrow_mut() = Some(vec![]);
770    }
771
772    pub fn complete(&self, objs: &TCObjects) {
773        if self.all_methods.borrow().is_some() {
774            return;
775        }
776        let mut all = self.methods.clone();
777        for tkey in self.embeddeds.iter() {
778            let embeded = &objs.types[*tkey].try_as_interface().unwrap();
779            embeded.complete(objs);
780            all.append(&mut embeded.all_methods().as_ref().unwrap().clone());
781        }
782        all.sort_by(compare_by_method_name!(&objs));
783        *self.all_methods.borrow_mut() = Some(all);
784    }
785}
786
787#[derive(Debug)]
788pub struct MapDetail {
789    key: TypeKey,
790    elem: TypeKey,
791}
792
793impl MapDetail {
794    pub fn new(key: TypeKey, elem: TypeKey) -> MapDetail {
795        MapDetail {
796            key: key,
797            elem: elem,
798        }
799    }
800
801    pub fn key(&self) -> TypeKey {
802        self.key
803    }
804
805    pub fn elem(&self) -> TypeKey {
806        self.elem
807    }
808}
809
810#[derive(Copy, Clone, Debug, PartialEq, Eq)]
811pub enum ChanDir {
812    SendRecv,
813    SendOnly,
814    RecvOnly,
815}
816
817#[derive(Debug)]
818pub struct ChanDetail {
819    dir: ChanDir,
820    elem: TypeKey,
821}
822
823impl ChanDetail {
824    pub fn new(dir: ChanDir, elem: TypeKey) -> ChanDetail {
825        ChanDetail {
826            dir: dir,
827            elem: elem,
828        }
829    }
830
831    pub fn dir(&self) -> ChanDir {
832        self.dir
833    }
834
835    pub fn elem(&self) -> TypeKey {
836        self.elem
837    }
838}
839
840#[derive(Debug)]
841pub struct NamedDetail {
842    obj: Option<ObjKey>,         // corresponding declared object
843    underlying: Option<TypeKey>, // possibly a Named during setup; never a Named once set up completely
844    methods: Vec<ObjKey>, // methods declared for this type (not the method set of this type); signatures are type-checked lazily
845}
846
847impl NamedDetail {
848    pub fn new(
849        obj: Option<ObjKey>,
850        underlying: Option<TypeKey>,
851        methods: Vec<ObjKey>,
852        objs: &TCObjects,
853    ) -> NamedDetail {
854        if cfg!(debug_assertions) && underlying.is_some() {
855            let t = &objs.types[underlying.unwrap()];
856            assert!(t.try_as_named().is_none());
857        }
858        //todo: where to set obj's typ to self?
859        NamedDetail {
860            obj: obj,
861            underlying: underlying,
862            methods: methods,
863        }
864    }
865
866    pub fn obj(&self) -> &Option<ObjKey> {
867        &self.obj
868    }
869
870    pub fn set_obj(&mut self, obj: ObjKey) {
871        self.obj = Some(obj)
872    }
873
874    pub fn methods(&self) -> &Vec<ObjKey> {
875        &self.methods
876    }
877
878    pub fn methods_mut(&mut self) -> &mut Vec<ObjKey> {
879        &mut self.methods
880    }
881
882    pub fn underlying(&self) -> TypeKey {
883        self.underlying.unwrap()
884    }
885
886    pub fn set_underlying(&mut self, t: TypeKey) {
887        self.underlying = Some(t);
888    }
889}
890
891// ----------------------------------------------------------------------------
892// utilities
893
894/// size_of only works for typed basic types for now
895/// it panics with untyped, and return the size of
896/// machine word size for all other types
897pub fn size_of(t: &TypeKey, objs: &TCObjects) -> usize {
898    let typ = &objs.types[*t].underlying_val(objs);
899    match typ {
900        Type::Basic(detail) => detail.size_of(),
901        _ => std_size_of::<usize>(),
902    }
903}
904
905/// underlying_type returns the underlying type of type 't'
906pub fn underlying_type(t: TypeKey, objs: &TCObjects) -> TypeKey {
907    let typ = &objs.types[t];
908    match typ.underlying() {
909        Some(ut) => ut,
910        None => t,
911    }
912}
913
914/// deep_underlying_type returns the 'deep' underlying type of type 't'
915/// chains only exist while named types are incomplete.
916pub fn deep_underlying_type(t: TypeKey, objs: &TCObjects) -> TypeKey {
917    let mut typ = &objs.types[t];
918    let mut ret = t;
919    loop {
920        match typ.underlying() {
921            Some(ut) => {
922                typ = &objs.types[ut];
923                ret = ut;
924                continue;
925            }
926            None => return ret,
927        }
928    }
929}
930
931pub fn is_named(t: TypeKey, objs: &TCObjects) -> bool {
932    objs.types[t].is_named()
933}
934
935pub fn is_boolean(t: TypeKey, objs: &TCObjects) -> bool {
936    objs.types[t].is_boolean(objs)
937}
938
939pub fn is_integer(t: TypeKey, objs: &TCObjects) -> bool {
940    objs.types[t].is_integer(objs)
941}
942
943pub fn is_unsigned(t: TypeKey, objs: &TCObjects) -> bool {
944    objs.types[t].is_unsigned(objs)
945}
946
947pub fn is_float(t: TypeKey, objs: &TCObjects) -> bool {
948    objs.types[t].is_float(objs)
949}
950
951pub fn is_complex(t: TypeKey, objs: &TCObjects) -> bool {
952    objs.types[t].is_complex(objs)
953}
954
955pub fn is_numeric(t: TypeKey, objs: &TCObjects) -> bool {
956    objs.types[t].is_numeric(objs)
957}
958
959pub fn is_string(t: TypeKey, objs: &TCObjects) -> bool {
960    objs.types[t].is_string(objs)
961}
962
963pub fn is_typed(t: TypeKey, objs: &TCObjects) -> bool {
964    objs.types[t].is_typed(objs)
965}
966
967pub fn is_untyped(t: TypeKey, objs: &TCObjects) -> bool {
968    objs.types[t].is_untyped(objs)
969}
970
971pub fn is_ordered(t: TypeKey, objs: &TCObjects) -> bool {
972    objs.types[t].is_ordered(objs)
973}
974
975pub fn is_const_type(t: TypeKey, objs: &TCObjects) -> bool {
976    objs.types[t].is_const_type(objs)
977}
978
979pub fn is_interface(t: TypeKey, objs: &TCObjects) -> bool {
980    objs.types[t].is_interface(objs)
981}
982
983/// has_nil reports whether a type includes the nil value.
984pub fn has_nil(t: TypeKey, objs: &TCObjects) -> bool {
985    objs.types[t].has_nil(objs)
986}
987
988/// comparable reports whether values of type T are comparable.
989pub fn comparable(t: TypeKey, objs: &TCObjects) -> bool {
990    objs.types[t].comparable(objs)
991}
992
993/// untyped_default_type returns the default "typed" type for an "untyped" type;
994/// it returns the incoming type for all other types. The default type
995/// for untyped nil is untyped nil.
996pub fn untyped_default_type(t: TypeKey, objs: &TCObjects) -> TypeKey {
997    objs.types[t].try_as_basic().map_or(t, |bt| match bt.typ() {
998        BasicType::UntypedBool => objs.universe().types()[&BasicType::Bool],
999        BasicType::UntypedInt => objs.universe().types()[&BasicType::Int],
1000        BasicType::UntypedRune => *objs.universe().rune(),
1001        BasicType::UntypedFloat => objs.universe().types()[&BasicType::Float64],
1002        BasicType::UntypedComplex => objs.universe().types()[&BasicType::Complex128],
1003        BasicType::UntypedString => objs.universe().types()[&BasicType::Str],
1004        _ => t,
1005    })
1006}
1007
1008/// identical reports whether x and y are identical types.
1009/// Receivers of Signature types are ignored.
1010pub fn identical(x: TypeKey, y: TypeKey, objs: &TCObjects) -> bool {
1011    identical_impl(x, y, true, &mut HashSet::new(), objs)
1012}
1013
1014/// identical_option is the same as identical except for the parameters
1015pub fn identical_option(x: Option<TypeKey>, y: Option<TypeKey>, objs: &TCObjects) -> bool {
1016    identical_impl_o(x, y, true, &mut HashSet::new(), objs)
1017}
1018
1019/// identical_ignore_tags reports whether x and y are identical types if tags are ignored.
1020/// Receivers of Signature types are ignored.
1021pub fn identical_ignore_tags(x: Option<TypeKey>, y: Option<TypeKey>, objs: &TCObjects) -> bool {
1022    identical_impl_o(x, y, false, &mut HashSet::new(), objs)
1023}
1024
1025/// identical_impl_o accepts wrapped TypeKeys
1026fn identical_impl_o(
1027    x: Option<TypeKey>,
1028    y: Option<TypeKey>,
1029    cmp_tags: bool,
1030    dup: &mut HashSet<(TypeKey, TypeKey)>,
1031    objs: &TCObjects,
1032) -> bool {
1033    if x == y {
1034        true
1035    } else if x.is_none() || y.is_none() {
1036        false
1037    } else {
1038        identical_impl(x.unwrap(), y.unwrap(), cmp_tags, dup, objs)
1039    }
1040}
1041
1042/// identical_impl implements the logic of identical
1043/// 'dup' is used to detect cycles.
1044fn identical_impl(
1045    x: TypeKey,
1046    y: TypeKey,
1047    cmp_tags: bool,
1048    dup: &mut HashSet<(TypeKey, TypeKey)>,
1049    objs: &TCObjects,
1050) -> bool {
1051    if x == y {
1052        return true;
1053    }
1054    let tx = &objs.types[x];
1055    let ty = &objs.types[y];
1056
1057    match (tx, ty) {
1058        (Type::Basic(bx), Type::Basic(by)) => bx.typ().real_type() == by.typ().real_type(),
1059        (Type::Array(ax), Type::Array(ay)) => {
1060            ax.len() == ay.len() && identical_impl(ax.elem(), ay.elem(), cmp_tags, dup, objs)
1061        }
1062        (Type::Slice(sx), Type::Slice(sy)) => {
1063            identical_impl(sx.elem(), sy.elem(), cmp_tags, dup, objs)
1064        }
1065        (Type::Struct(sx), Type::Struct(sy)) => {
1066            if sx.fields().len() == sy.fields().len() {
1067                !sx.fields().iter().enumerate().any(|(i, f)| {
1068                    let of = &objs.lobjs[*f];
1069                    let og = &objs.lobjs[sy.fields()[i]];
1070                    (of.var_embedded() != og.var_embedded())
1071                        || (cmp_tags && sx.tag(i) != sy.tag(i))
1072                        || (!of.same_id(og.pkg(), og.name(), objs))
1073                        || (!identical_impl_o(of.typ(), og.typ(), cmp_tags, dup, objs))
1074                })
1075            } else {
1076                false
1077            }
1078        }
1079        (Type::Pointer(px), Type::Pointer(py)) => {
1080            identical_impl(px.base(), py.base(), cmp_tags, dup, objs)
1081        }
1082        (Type::Tuple(tx), Type::Tuple(ty)) => {
1083            if tx.vars().len() == ty.vars().len() {
1084                !tx.vars().iter().enumerate().any(|(i, v)| {
1085                    let ov = &objs.lobjs[*v];
1086                    let ow = &objs.lobjs[ty.vars()[i]];
1087                    !identical_impl_o(ov.typ(), ow.typ(), cmp_tags, dup, objs)
1088                })
1089            } else {
1090                false
1091            }
1092        }
1093        (Type::Signature(sx), Type::Signature(sy)) => {
1094            sx.variadic() == sy.variadic()
1095                && identical_impl(sx.params(), sy.params(), cmp_tags, dup, objs)
1096                && identical_impl(sx.results(), sy.results(), cmp_tags, dup, objs)
1097        }
1098        (Type::Interface(ix), Type::Interface(iy)) => {
1099            match (ix.all_methods().as_ref(), iy.all_methods().as_ref()) {
1100                (None, None) => true,
1101                (Some(a), Some(b)) => {
1102                    if a.len() == b.len() {
1103                        // Interface types are the only types where cycles can occur
1104                        // that are not "terminated" via named types; and such cycles
1105                        // can only be created via method parameter types that are
1106                        // anonymous interfaces (directly or indirectly) embedding
1107                        // the current interface. Example:
1108                        //
1109                        //    type T interface {
1110                        //        m() interface{T}
1111                        //    }
1112                        //
1113                        // If two such (differently named) interfaces are compared,
1114                        // endless recursion occurs if the cycle is not detected.
1115                        //
1116                        // If x and y were compared before, they must be equal
1117                        // (if they were not, the recursion would have stopped);
1118                        let pair = (x, y);
1119                        if dup.get(&pair).is_some() {
1120                            // pair got compared before
1121                            true
1122                        } else {
1123                            dup.insert(pair);
1124                            !a.iter().enumerate().any(|(i, k)| {
1125                                let ox = &objs.lobjs[*k];
1126                                let oy = &objs.lobjs[b[i]];
1127                                ox.id(objs) != oy.id(objs)
1128                                    || !identical_impl_o(ox.typ(), oy.typ(), cmp_tags, dup, objs)
1129                            })
1130                        }
1131                    } else {
1132                        false
1133                    }
1134                }
1135                _ => false,
1136            }
1137        }
1138        (Type::Map(mx), Type::Map(my)) => {
1139            identical_impl(mx.key(), my.key(), cmp_tags, dup, objs)
1140                && identical_impl(mx.elem(), my.elem(), cmp_tags, dup, objs)
1141        }
1142        (Type::Chan(cx), Type::Chan(cy)) => {
1143            cx.dir() == cy.dir() && identical_impl(cx.elem(), cy.elem(), cmp_tags, dup, objs)
1144        }
1145        (Type::Named(nx), Type::Named(ny)) => nx.obj() == ny.obj(),
1146        _ => false,
1147    }
1148}
1149
1150pub fn fmt_type(t: Option<TypeKey>, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
1151    fmt_type_impl(t, f, &mut HashSet::new(), objs)
1152}
1153
1154pub fn fmt_signature(t: TypeKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
1155    fmt_signature_impl(t, f, &mut HashSet::new(), objs)
1156}
1157
1158fn fmt_type_impl(
1159    t: Option<TypeKey>,
1160    f: &mut fmt::Formatter<'_>,
1161    visited: &mut HashSet<TypeKey>,
1162    objs: &TCObjects,
1163) -> fmt::Result {
1164    if t.is_none() {
1165        return f.write_str("<nil>");
1166    }
1167    let tkey = t.unwrap();
1168    if visited.get(&tkey).is_some() {
1169        return tkey.fmt(f);
1170    }
1171    visited.insert(tkey);
1172    let typ = &objs.types[tkey];
1173    match typ {
1174        Type::Basic(detail) => {
1175            if detail.typ == BasicType::UnsafePointer {
1176                f.write_str("unsafe.")?;
1177            }
1178            write!(f, "{}", detail.name)?;
1179        }
1180        Type::Array(detail) => {
1181            match detail.len {
1182                Some(i) => write!(f, "[{}]", i)?,
1183                None => f.write_str("[unknown]")?,
1184            };
1185            fmt_type_impl(Some(detail.elem), f, visited, objs)?;
1186        }
1187        Type::Slice(detail) => {
1188            f.write_str("[]")?;
1189            fmt_type_impl(Some(detail.elem), f, visited, objs)?;
1190        }
1191        Type::Struct(detail) => {
1192            f.write_str("struct{")?;
1193            for (i, key) in detail.fields().iter().enumerate() {
1194                if i > 0 {
1195                    f.write_str("; ")?;
1196                }
1197                let field = &objs.lobjs[*key];
1198                if !field.var_embedded() {
1199                    write!(f, "{} ", field.name())?;
1200                }
1201                fmt_type_impl(field.typ(), f, visited, objs)?;
1202                if let Some(tag) = detail.tag(i) {
1203                    write!(f, " {}", tag)?;
1204                }
1205            }
1206            f.write_str("}")?;
1207        }
1208        Type::Pointer(detail) => {
1209            f.write_char('*')?;
1210            fmt_type_impl(Some(detail.base()), f, visited, objs)?;
1211        }
1212        Type::Tuple(_) => {
1213            fmt_tuple(tkey, false, f, visited, objs)?;
1214        }
1215        Type::Signature(_) => {
1216            f.write_str("func")?;
1217            fmt_signature_impl(t.unwrap(), f, visited, objs)?;
1218        }
1219        Type::Interface(detail) => {
1220            f.write_str("interface{")?;
1221            for (i, k) in detail.methods().iter().enumerate() {
1222                if i > 0 {
1223                    f.write_str("; ")?;
1224                }
1225                let mobj = &objs.lobjs[*k];
1226                f.write_str(mobj.name())?;
1227                fmt_signature_impl(mobj.typ().unwrap(), f, visited, objs)?;
1228            }
1229            for (i, k) in detail.embeddeds().iter().enumerate() {
1230                if i > 0 || detail.methods().len() > 0 {
1231                    f.write_str("; ")?;
1232                }
1233                fmt_type_impl(Some(*k), f, visited, objs)?;
1234            }
1235            if detail.all_methods().is_none() {
1236                f.write_str(" /* incomplete */")?;
1237            }
1238            f.write_char('}')?;
1239        }
1240        Type::Map(detail) => {
1241            f.write_str("map[")?;
1242            fmt_type_impl(Some(detail.key()), f, visited, objs)?;
1243            f.write_char(']')?;
1244            fmt_type_impl(Some(detail.elem()), f, visited, objs)?;
1245        }
1246        Type::Chan(detail) => {
1247            let (s, paren) = match detail.dir() {
1248                ChanDir::SendRecv => ("chan ", {
1249                    // chan (<-chan T) requires parentheses
1250                    let elm = &objs.types[detail.elem()];
1251                    if let Some(c) = elm.try_as_chan() {
1252                        c.dir() == ChanDir::RecvOnly
1253                    } else {
1254                        false
1255                    }
1256                }),
1257                ChanDir::SendOnly => ("chan<- ", false),
1258                ChanDir::RecvOnly => ("<-chan ", false),
1259            };
1260            f.write_str(s)?;
1261            if paren {
1262                f.write_char('(')?;
1263            }
1264            fmt_type_impl(Some(detail.elem()), f, visited, objs)?;
1265            if paren {
1266                f.write_char(')')?;
1267            }
1268        }
1269        Type::Named(detail) => {
1270            if let Some(okey) = detail.obj() {
1271                let o = &objs.lobjs[*okey];
1272                if let Some(pkg) = o.pkg() {
1273                    objs.pkgs[pkg].fmt_with_qualifier(f, objs.fmt_qualifier.as_ref())?;
1274                }
1275                f.write_str(o.name())?;
1276            } else {
1277                f.write_str("<Named w/o object>")?;
1278            }
1279        }
1280    }
1281    Ok(())
1282}
1283
1284fn fmt_signature_impl(
1285    t: TypeKey,
1286    f: &mut fmt::Formatter<'_>,
1287    visited: &mut HashSet<TypeKey>,
1288    objs: &TCObjects,
1289) -> fmt::Result {
1290    let sig = &objs.types[t].try_as_signature().unwrap();
1291    fmt_tuple(sig.params(), sig.variadic(), f, visited, &objs)?;
1292    f.write_char(' ')?;
1293    let results = &objs.types[sig.results()].try_as_tuple().unwrap();
1294    if results.vars().len() == 1 {
1295        let obj = &objs.lobjs[results.vars()[0]];
1296        if obj.name().is_empty() {
1297            // single unnamed result
1298            return fmt_type_impl(obj.typ(), f, visited, objs);
1299        }
1300    }
1301    // multiple or named result(s)
1302    fmt_tuple(sig.results(), false, f, visited, objs)
1303}
1304
1305fn fmt_tuple(
1306    tkey: TypeKey,
1307    variadic: bool,
1308    f: &mut fmt::Formatter<'_>,
1309    visited: &mut HashSet<TypeKey>,
1310    objs: &TCObjects,
1311) -> fmt::Result {
1312    f.write_char('(')?;
1313    let tuple = &objs.types[tkey].try_as_tuple().unwrap();
1314    for (i, v) in tuple.vars().iter().enumerate() {
1315        if i > 0 {
1316            f.write_str(", ")?;
1317        }
1318        let obj = &objs.lobjs[*v];
1319        if !obj.name().is_empty() {
1320            write!(f, "{} ", obj.name())?;
1321        }
1322        let tkey = obj.typ();
1323        if variadic && i == tuple.vars().len() - 1 {
1324            let utype = underlying_type(tkey.unwrap(), &objs);
1325            let typ = &objs.types[utype];
1326            match typ {
1327                Type::Slice(detail) => {
1328                    f.write_str("...")?;
1329                    fmt_type_impl(Some(detail.elem()), f, visited, objs)?;
1330                }
1331                Type::Basic(detail) => {
1332                    // special case:
1333                    // append(s, "foo"...) leads to signature func([]byte, string...)
1334                    assert!(detail.typ() == BasicType::Str);
1335                    fmt_type_impl(tkey, f, visited, objs)?;
1336                    f.write_str("...")?;
1337                }
1338                _ => unreachable!(),
1339            }
1340        } else {
1341            fmt_type_impl(tkey, f, visited, objs)?;
1342        }
1343    }
1344    f.write_char(')')?;
1345    Ok(())
1346}