go_types/
typ.rs

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