tc_assign.mx raw

   1  package main
   2  
   3  // Identical reports whether T and U are identical types under Moxie rules:
   4  // - string = []byte (Moxie text unification)
   5  // - int = int32, uint = uint32 (enforced via universe scope, but checked here too)
   6  func Identical(T, U Type) bool {
   7  	if T == U {
   8  		return true
   9  	}
  10  	if T == nil || U == nil {
  11  		return false
  12  	}
  13  	switch t := T.(type) {
  14  	case *Basic:
  15  		u, ok := U.(*Basic)
  16  		if !ok {
  17  			if t.kind == TCString {
  18  				if sl, ok2 := U.(*Slice); ok2 {
  19  					if eb, ok3 := sl.elem.(*Basic); ok3 && eb.kind == Uint8 {
  20  						return true
  21  					}
  22  				}
  23  			}
  24  			return false
  25  		}
  26  		// Moxie: string and []byte share kind TCString.
  27  		tk := normaliseKind(t.kind)
  28  		uk := normaliseKind(u.kind)
  29  		return tk == uk
  30  	case *Pointer:
  31  		u, ok := U.(*Pointer)
  32  		return ok && Identical(t.base, u.base)
  33  	case *Array:
  34  		u, ok := U.(*Array)
  35  		return ok && t.len == u.len && Identical(t.elem, u.elem)
  36  	case *Slice:
  37  		u, ok := U.(*Slice)
  38  		if !ok {
  39  			// []byte = string in Moxie
  40  			if b, ok2 := U.(*Basic); ok2 && b.kind == TCString {
  41  				if eb, ok3 := t.elem.(*Basic); ok3 && eb.kind == Uint8 {
  42  					return true
  43  				}
  44  			}
  45  			return false
  46  		}
  47  		return Identical(t.elem, u.elem)
  48  	case *TCMap:
  49  		u, ok := U.(*TCMap)
  50  		return ok && Identical(t.key, u.key) && Identical(t.elem, u.elem)
  51  	case *TCChan:
  52  		u, ok := U.(*TCChan)
  53  		return ok && t.dir == u.dir && Identical(t.elem, u.elem)
  54  	case *TCStruct:
  55  		u, ok := U.(*TCStruct)
  56  		if !ok || t.NumFields() != u.NumFields() {
  57  			return false
  58  		}
  59  		for i := range t.fields {
  60  			tf := t.fields[i]
  61  			uf := u.fields[i]
  62  			if tf.name != uf.name || tf.anonymous != uf.anonymous {
  63  				return false
  64  			}
  65  			if !Identical(tf.typ, uf.typ) {
  66  				return false
  67  			}
  68  		}
  69  		return true
  70  	case *TCInterface:
  71  		u, ok := U.(*TCInterface)
  72  		if !ok {
  73  			return false
  74  		}
  75  		if t.NumMethods() != u.NumMethods() {
  76  			return false
  77  		}
  78  		for i, tm := range t.allMethods {
  79  			um := u.allMethods[i]
  80  			if tm.name != um.name || !Identical(tm.sig, um.sig) {
  81  				return false
  82  			}
  83  		}
  84  		return true
  85  	case *Signature:
  86  		u, ok := U.(*Signature)
  87  		if !ok {
  88  			return false
  89  		}
  90  		if t.variadic != u.variadic {
  91  			return false
  92  		}
  93  		if !identicalTuples(t.params, u.params) || !identicalTuples(t.results, u.results) {
  94  			return false
  95  		}
  96  		return true
  97  	case *Named:
  98  		u, ok := U.(*Named)
  99  		return ok && t.obj == u.obj
 100  	case *TypeParam:
 101  		u, ok := U.(*TypeParam)
 102  		return ok && t.id == u.id
 103  	case *Tuple:
 104  		u, ok := U.(*Tuple)
 105  		return ok && identicalTuples(t, u)
 106  	}
 107  	return false
 108  }
 109  
 110  func identicalTuples(a, b *Tuple) bool {
 111  	la, lb := tupleLen(a), tupleLen(b)
 112  	if la != lb {
 113  		return false
 114  	}
 115  	for i := 0; i < la; i++ {
 116  		if !Identical(a.vars[i].typ, b.vars[i].typ) {
 117  			return false
 118  		}
 119  	}
 120  	return true
 121  }
 122  
 123  func tupleLen(t *Tuple) int {
 124  	if t == nil {
 125  		return 0
 126  	}
 127  	return t.Len()
 128  }
 129  
 130  // normaliseKind maps int/uint to their 32-bit equivalents for identity checks.
 131  func normaliseKind(k BasicKind) BasicKind {
 132  	return k // int=int32 is handled by the universe scope; no extra mapping needed
 133  }
 134  
 135  // Assignable reports whether a value of type V is assignable to type T
 136  // under Moxie's type rules (spec Assignability, plus Moxie extensions).
 137  func Assignable(V, T Type) bool {
 138  	if V == nil || T == nil {
 139  		return V == T
 140  	}
 141  	// Identical types are always assignable.
 142  	if Identical(V, T) {
 143  		return true
 144  	}
 145  	// Moxie extension: string = []byte anywhere.
 146  	if isTextType(V) && isTextType(T) {
 147  		return true
 148  	}
 149  	// Untyped constants are assignable to any numeric/bool/string type they fit in.
 150  	if bv, ok := V.(*Basic); ok && bv.info&IsUntyped != 0 {
 151  		return untypedAssignable(bv, T)
 152  	}
 153  	// nil is assignable to pointer, slice, map, chan, func, interface.
 154  	if V == Typ[UntypedNil] {
 155  		return isNilable(T)
 156  	}
 157  	// V's underlying type identical to T's underlying type, and at least one is unnamed.
 158  	vu, tu := V.Underlying(), T.Underlying()
 159  	if Identical(vu, tu) {
 160  		_, vNamed := V.(*Named)
 161  		_, tNamed := T.(*Named)
 162  		if !vNamed || !tNamed {
 163  			return true
 164  		}
 165  	}
 166  	// T is an interface and V implements it.
 167  	if iface, ok := T.Underlying().(*TCInterface); ok {
 168  		return Implements(V, iface)
 169  	}
 170  	// Directional channel: bidirectional chan is assignable to directed chan.
 171  	if tc, ok := T.(*TCChan); ok {
 172  		if vc, ok2 := V.(*TCChan); ok2 {
 173  			if Identical(tc.elem, vc.elem) {
 174  				return vc.dir == TCSendRecv || vc.dir == tc.dir
 175  			}
 176  		}
 177  	}
 178  	return false
 179  }
 180  
 181  func isNilable(T Type) bool {
 182  	switch T.Underlying().(type) {
 183  	case *Pointer, *Slice, *TCMap, *TCChan, *Signature, *TCInterface:
 184  		return true
 185  	}
 186  	return false
 187  }
 188  
 189  func untypedAssignable(V *Basic, T Type) bool {
 190  	b, ok := T.Underlying().(*Basic)
 191  	if !ok {
 192  		return false
 193  	}
 194  	switch V.kind {
 195  	case UntypedBool:
 196  		return b.info&IsBoolean != 0
 197  	case UntypedInt, UntypedRune:
 198  		return b.info&IsInteger != 0 || b.info&IsFloat != 0
 199  	case UntypedFloat:
 200  		return b.info&IsFloat != 0
 201  	case UntypedString:
 202  		return b.info&IsString != 0
 203  	}
 204  	return false
 205  }
 206  
 207  // isTextType returns true if T is string or []byte under Moxie's unified model.
 208  func isTextType(T Type) bool {
 209  	if b, ok := T.Underlying().(*Basic); ok && b.info&IsString != 0 {
 210  		return true
 211  	}
 212  	if sl, ok := T.Underlying().(*Slice); ok {
 213  		if b, ok2 := sl.elem.Underlying().(*Basic); ok2 && b.kind == Uint8 {
 214  			return true
 215  		}
 216  	}
 217  	return false
 218  }
 219  
 220  // Implements reports whether type T implements interface I.
 221  func Implements(T Type, I *TCInterface) bool {
 222  	if I.IsEmpty() {
 223  		return true
 224  	}
 225  	// Collect T's method set.
 226  	ms := methodSet(T)
 227  	for _, im := range I.allMethods {
 228  		m, ok := ms[im.name]
 229  		if !ok {
 230  			return false
 231  		}
 232  		if !Identical(m.Signature(), im.sig) {
 233  			return false
 234  		}
 235  	}
 236  	return true
 237  }
 238  
 239  // methodSet returns the named method set of T as a name->Func map.
 240  // Includes methods from *T if T is a named type (pointer receiver methods).
 241  func methodSet(T Type) map[string]*TCFunc {
 242  	ms := map[string]*TCFunc{}
 243  	collectMethods(T, ms, false)
 244  	return ms
 245  }
 246  
 247  func collectMethods(T Type, ms map[string]*TCFunc, ptrOk bool) {
 248  	switch t := T.(type) {
 249  	case *Named:
 250  		for _, m := range t.methods {
 251  			if _, dup := ms[m.name]; !dup {
 252  				ms[m.name] = m
 253  			}
 254  		}
 255  		// Also collect pointer receiver methods if T is addressable.
 256  		if ptrOk {
 257  			collectMethods(NewPointer(T), ms, false)
 258  		}
 259  		collectMethods(t.underlying, ms, ptrOk)
 260  	case *Pointer:
 261  		if named, ok := t.base.(*Named); ok {
 262  			for _, m := range named.methods {
 263  				if _, dup := ms[m.name]; !dup {
 264  					ms[m.name] = m
 265  				}
 266  			}
 267  		}
 268  	case *TCInterface:
 269  		for _, m := range t.allMethods {
 270  			if _, dup := ms[m.name]; !dup {
 271  				ms[m.name] = NewTCFunc(nil, m.name, m.sig)
 272  			}
 273  		}
 274  	}
 275  }
 276