diff --git a/compiler/interface.go b/compiler/interface.go index ca9fc9ba..5eb939d1 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -112,6 +112,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { typeFieldTypes = append(typeFieldTypes, types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "pkglen", types.Typ[types.Uintptr]), + types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "len", types.Typ[types.Uintptr]), types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(typ.Obj().Name())))), ) @@ -172,9 +174,32 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} case *types.Named: name := typ.Obj().Name() + + pkg := typ.Obj().Pkg() + var pkgpath string + pkgpathName := "reflect/types.type.pkgpath.empty" + if pkg != nil { + pkgpath = pkg.Path() + pkgpathName = "reflect/types.type.pkgpath:" + pkgpath + } + + pkgpathInitializer := c.ctx.ConstString(pkgpath, false) + pkgpathGlobal := llvm.AddGlobal(c.mod, pkgpathInitializer.Type(), pkgpathName) + pkgpathGlobal.SetInitializer(pkgpathInitializer) + pkgpathGlobal.SetAlignment(1) + pkgpathGlobal.SetUnnamedAddr(true) + pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage) + pkgpathGlobal.SetGlobalConstant(true) + pkgpathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{ + llvm.ConstInt(c.ctx.Int32Type(), 0, false), + llvm.ConstInt(c.ctx.Int32Type(), 0, false), + }) + typeFields = []llvm.Value{ - c.getTypeCode(types.NewPointer(typ)), // ptrTo - c.getTypeCode(typ.Underlying()), // underlying + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Underlying()), // underlying + llvm.ConstInt(c.uintptrType, uint64(len(pkgpath)), false), // pkgpath length + pkgpathPtr, // pkgpath pointer llvm.ConstInt(c.uintptrType, uint64(len(name)), false), // length c.ctx.ConstString(name, false), // name } diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index 7b44122f..aa816a03 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -9,7 +9,8 @@ target triple = "wasm32-unknown-wasi" @"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4 @"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:int" }, align 4 @"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:named:error" }, align 4 -@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr, i32, [5 x i8] } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 5, [5 x i8] c"error" }, align 4 +@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr, i32, ptr, i32, [5 x i8] } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, ptr @"reflect/types.type.pkgpath.empty", i32 5, [5 x i8] c"error" }, align 4 +@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [0 x i8] zeroinitializer, align 1 @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4 @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4 diff --git a/src/reflect/type.go b/src/reflect/type.go index 544e8f8a..dd8c9a79 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -50,6 +50,8 @@ // meta uint8 // ptrTo *typeStruct // elem *typeStruct // underlying type +// plen uintptr // length of pkgpath +// pkg *byte // pkgpath // nlem uintptr // length of name // name [1]byte // actual name; length nlem // @@ -428,6 +430,8 @@ type namedType struct { rawType ptrTo *rawType elem *rawType + plen uintptr + pkg *byte nlen uintptr name [1]byte } @@ -489,8 +493,7 @@ func pointerTo(t *rawType) *rawType { func (t *rawType) String() string { if t.isNamed() { - // TODO(dgryski): `main` until pkgPath support lands - return "" + "." + t.Name() + return t.PkgPath() + "." + t.Name() } switch t.Kind() { @@ -918,8 +921,13 @@ func (t rawType) MethodByName(name string) (Method, bool) { panic("unimplemented: (reflect.Type).MethodByName()") } -func (t rawType) PkgPath() string { - panic("unimplemented: (reflect.Type).PkgPath()") +func (t *rawType) PkgPath() string { + if t.isNamed() { + ntype := (*namedType)(unsafe.Pointer(t)) + return unsafe.String(ntype.pkg, ntype.plen) + } + + return "" } func (t rawType) FieldByName(name string) (StructField, bool) { diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index f0c5cd28..51f38ac8 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -221,6 +221,10 @@ func TestNamedTypes(t *testing.T) { t.Errorf("TypeOf.Name()=%v, want %v", got, want) } + if got, want := TypeOf(named).String(), "reflect_test.namedString"; got != want { + t.Errorf("TypeOf.String()=%v, want %v", got, want) + } + m := make(map[[4]uint16]string) if got, want := TypeOf(m).String(), "map[[4]uint16]string"; got != want {