github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-convert-interface.c (about) 1 /* go-convert-interface.c -- convert interfaces for Go. 2 3 Copyright 2009 The Go Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style 5 license that can be found in the LICENSE file. */ 6 7 #include "runtime.h" 8 #include "go-alloc.h" 9 #include "go-assert.h" 10 #include "go-panic.h" 11 #include "go-string.h" 12 #include "go-type.h" 13 #include "interface.h" 14 15 /* This is called when converting one interface type into another 16 interface type. LHS_DESCRIPTOR is the type descriptor of the 17 resulting interface. RHS_DESCRIPTOR is the type descriptor of the 18 object being converted. This builds and returns a new interface 19 method table. If any method in the LHS_DESCRIPTOR interface is not 20 implemented by the object, the conversion fails. If the conversion 21 fails, then if MAY_FAIL is true this returns NULL; otherwise, it 22 panics. */ 23 24 void * 25 __go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor, 26 const struct __go_type_descriptor *rhs_descriptor, 27 _Bool may_fail) 28 { 29 const struct __go_interface_type *lhs_interface; 30 int lhs_method_count; 31 const struct __go_interface_method* lhs_methods; 32 const void **methods; 33 const struct __go_uncommon_type *rhs_uncommon; 34 int rhs_method_count; 35 const struct __go_method *p_rhs_method; 36 int i; 37 38 if (rhs_descriptor == NULL) 39 { 40 /* A nil value always converts to nil. */ 41 return NULL; 42 } 43 44 __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE); 45 lhs_interface = (const struct __go_interface_type *) lhs_descriptor; 46 lhs_method_count = lhs_interface->__methods.__count; 47 lhs_methods = ((const struct __go_interface_method *) 48 lhs_interface->__methods.__values); 49 50 /* This should not be called for an empty interface. */ 51 __go_assert (lhs_method_count > 0); 52 53 rhs_uncommon = rhs_descriptor->__uncommon; 54 if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0) 55 { 56 struct __go_empty_interface panic_arg; 57 58 if (may_fail) 59 return NULL; 60 61 runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection, 62 lhs_descriptor->__reflection, 63 lhs_methods[0].__name, 64 &panic_arg); 65 __go_panic (panic_arg); 66 } 67 68 rhs_method_count = rhs_uncommon->__methods.__count; 69 p_rhs_method = ((const struct __go_method *) 70 rhs_uncommon->__methods.__values); 71 72 methods = NULL; 73 74 for (i = 0; i < lhs_method_count; ++i) 75 { 76 const struct __go_interface_method *p_lhs_method; 77 78 p_lhs_method = &lhs_methods[i]; 79 80 while (rhs_method_count > 0 81 && (!__go_ptr_strings_equal (p_lhs_method->__name, 82 p_rhs_method->__name) 83 || !__go_ptr_strings_equal (p_lhs_method->__pkg_path, 84 p_rhs_method->__pkg_path))) 85 { 86 ++p_rhs_method; 87 --rhs_method_count; 88 } 89 90 if (rhs_method_count == 0 91 || !__go_type_descriptors_equal (p_lhs_method->__type, 92 p_rhs_method->__mtype)) 93 { 94 struct __go_empty_interface panic_arg; 95 96 if (methods != NULL) 97 __go_free (methods); 98 99 if (may_fail) 100 return NULL; 101 102 runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection, 103 lhs_descriptor->__reflection, 104 p_lhs_method->__name, &panic_arg); 105 __go_panic (panic_arg); 106 } 107 108 if (methods == NULL) 109 { 110 methods = (const void **) __go_alloc ((lhs_method_count + 1) 111 * sizeof (void *)); 112 113 /* The first field in the method table is always the type of 114 the object. */ 115 methods[0] = rhs_descriptor; 116 } 117 118 methods[i + 1] = p_rhs_method->__function; 119 } 120 121 return methods; 122 } 123 124 /* This is called by the compiler to convert a value from one 125 interface type to another. */ 126 127 void * 128 __go_convert_interface (const struct __go_type_descriptor *lhs_descriptor, 129 const struct __go_type_descriptor *rhs_descriptor) 130 { 131 return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0); 132 }