f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
133 lines
3.8 KiB
C
133 lines
3.8 KiB
C
/* go-convert-interface.c -- convert interfaces for Go.
|
|
|
|
Copyright 2009 The Go Authors. All rights reserved.
|
|
Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file. */
|
|
|
|
#include "runtime.h"
|
|
#include "go-alloc.h"
|
|
#include "go-assert.h"
|
|
#include "go-panic.h"
|
|
#include "go-string.h"
|
|
#include "go-type.h"
|
|
#include "interface.h"
|
|
|
|
/* This is called when converting one interface type into another
|
|
interface type. LHS_DESCRIPTOR is the type descriptor of the
|
|
resulting interface. RHS_DESCRIPTOR is the type descriptor of the
|
|
object being converted. This builds and returns a new interface
|
|
method table. If any method in the LHS_DESCRIPTOR interface is not
|
|
implemented by the object, the conversion fails. If the conversion
|
|
fails, then if MAY_FAIL is true this returns NULL; otherwise, it
|
|
panics. */
|
|
|
|
void *
|
|
__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
|
|
const struct __go_type_descriptor *rhs_descriptor,
|
|
_Bool may_fail)
|
|
{
|
|
const struct __go_interface_type *lhs_interface;
|
|
int lhs_method_count;
|
|
const struct __go_interface_method* lhs_methods;
|
|
const void **methods;
|
|
const struct __go_uncommon_type *rhs_uncommon;
|
|
int rhs_method_count;
|
|
const struct __go_method *p_rhs_method;
|
|
int i;
|
|
|
|
if (rhs_descriptor == NULL)
|
|
{
|
|
/* A nil value always converts to nil. */
|
|
return NULL;
|
|
}
|
|
|
|
__go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
|
|
lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
|
|
lhs_method_count = lhs_interface->__methods.__count;
|
|
lhs_methods = ((const struct __go_interface_method *)
|
|
lhs_interface->__methods.__values);
|
|
|
|
/* This should not be called for an empty interface. */
|
|
__go_assert (lhs_method_count > 0);
|
|
|
|
rhs_uncommon = rhs_descriptor->__uncommon;
|
|
if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
|
|
{
|
|
struct __go_empty_interface panic_arg;
|
|
|
|
if (may_fail)
|
|
return NULL;
|
|
|
|
runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
|
|
lhs_descriptor->__reflection,
|
|
lhs_methods[0].__name,
|
|
&panic_arg);
|
|
__go_panic (panic_arg);
|
|
}
|
|
|
|
rhs_method_count = rhs_uncommon->__methods.__count;
|
|
p_rhs_method = ((const struct __go_method *)
|
|
rhs_uncommon->__methods.__values);
|
|
|
|
methods = NULL;
|
|
|
|
for (i = 0; i < lhs_method_count; ++i)
|
|
{
|
|
const struct __go_interface_method *p_lhs_method;
|
|
|
|
p_lhs_method = &lhs_methods[i];
|
|
|
|
while (rhs_method_count > 0
|
|
&& (!__go_ptr_strings_equal (p_lhs_method->__name,
|
|
p_rhs_method->__name)
|
|
|| !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
|
|
p_rhs_method->__pkg_path)))
|
|
{
|
|
++p_rhs_method;
|
|
--rhs_method_count;
|
|
}
|
|
|
|
if (rhs_method_count == 0
|
|
|| !__go_type_descriptors_equal (p_lhs_method->__type,
|
|
p_rhs_method->__mtype))
|
|
{
|
|
struct __go_empty_interface panic_arg;
|
|
|
|
if (methods != NULL)
|
|
__go_free (methods);
|
|
|
|
if (may_fail)
|
|
return NULL;
|
|
|
|
runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
|
|
lhs_descriptor->__reflection,
|
|
p_lhs_method->__name, &panic_arg);
|
|
__go_panic (panic_arg);
|
|
}
|
|
|
|
if (methods == NULL)
|
|
{
|
|
methods = (const void **) __go_alloc ((lhs_method_count + 1)
|
|
* sizeof (void *));
|
|
|
|
/* The first field in the method table is always the type of
|
|
the object. */
|
|
methods[0] = rhs_descriptor;
|
|
}
|
|
|
|
methods[i + 1] = p_rhs_method->__function;
|
|
}
|
|
|
|
return methods;
|
|
}
|
|
|
|
/* This is called by the compiler to convert a value from one
|
|
interface type to another. */
|
|
|
|
void *
|
|
__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
|
|
const struct __go_type_descriptor *rhs_descriptor)
|
|
{
|
|
return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
|
|
}
|