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  }