Merge "[dev.typeparams] all: merge master (37f9a8f) into dev.typeparams" into dev.typeparams
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index c0346c0..c94f19f 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -186,6 +186,7 @@
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
typecheck.InitUniverse()
+ typecheck.InitRuntime()
// Parse and typecheck input.
noder.LoadPackage(flag.Args())
@@ -194,7 +195,6 @@
// Prepare for backend processing. This must happen before pkginit,
// because it generates itabs for initializing global variables.
- typecheck.InitRuntime()
ssagen.InitConfig()
// Build init task.
diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go
index 7291138..23e9446 100644
--- a/src/cmd/compile/internal/noder/linker.go
+++ b/src/cmd/compile/internal/noder/linker.go
@@ -209,8 +209,6 @@
pri, ok := bodyReader[name.Func]
assert(ok)
- w.sync(syncAddBody)
- w.sync(syncImplicitTypes)
w.reloc(relocBody, l.relocIdx(pri.pr, relocBody, pri.idx))
}
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index d2fe575..0423fcc 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -16,6 +16,7 @@
"cmd/compile/internal/deadcode"
"cmd/compile/internal/dwarfgen"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/reflectdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
@@ -104,8 +105,9 @@
// separately so that it doesn't take up space in every reader
// instance.
- curfn *ir.Func
- locals []*ir.Name
+ curfn *ir.Func
+ locals []*ir.Name
+ closureVars []*ir.Name
funarghack bool
@@ -419,7 +421,7 @@
if len(fields) == 0 {
return types.Types[types.TINTER] // empty interface
}
- return types.NewInterface(tpkg, fields)
+ return r.needWrapper(types.NewInterface(tpkg, fields))
}
func (r *reader) structType() *types.Type {
@@ -440,7 +442,7 @@
}
fields[i] = f
}
- return types.NewStruct(tpkg, fields)
+ return r.needWrapper(types.NewStruct(tpkg, fields))
}
func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type {
@@ -597,6 +599,10 @@
typ.Methods().Set(methods)
}
+ if !typ.IsPtr() {
+ r.needWrapper(typ)
+ }
+
return name
case objVar:
@@ -770,10 +776,10 @@
Cost: int32(r.len()),
CanDelayResults: r.bool(),
}
- r.addBody(name.Func)
+ r.addBody(name.Func, r.explicits)
}
} else {
- r.addBody(name.Func)
+ r.addBody(name.Func, r.explicits)
}
r.sync(syncEOF)
}
@@ -835,25 +841,7 @@
// constructed.
var todoBodies []*ir.Func
-// Keep in sync with writer.implicitTypes
-// Also see comment there for why r.implicits and r.explicits should
-// never both be non-empty.
-func (r *reader) implicitTypes() []*types.Type {
- r.sync(syncImplicitTypes)
-
- implicits := r.implicits
- if len(implicits) == 0 {
- implicits = r.explicits
- } else {
- assert(len(r.explicits) == 0)
- }
- return implicits
-}
-
-func (r *reader) addBody(fn *ir.Func) {
- r.sync(syncAddBody)
-
- implicits := r.implicitTypes()
+func (r *reader) addBody(fn *ir.Func, implicits []*types.Type) {
pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits}
bodyReader[fn] = pri
@@ -872,7 +860,7 @@
func (r *reader) funcBody(fn *ir.Func) {
r.curfn = fn
- r.locals = fn.ClosureVars
+ r.closureVars = fn.ClosureVars
// TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we
// don't have to set ir.CurFunc.
@@ -999,7 +987,10 @@
func (r *reader) useLocal() *ir.Name {
r.sync(syncUseObjLocal)
- return r.locals[r.len()]
+ if r.bool() {
+ return r.locals[r.len()]
+ }
+ return r.closureVars[r.len()]
}
func (r *reader) openScope() {
@@ -1083,8 +1074,11 @@
case stmtAssign:
pos := r.pos()
- names, lhs := r.assignList()
+
+ // TODO(mdempsky): After quirks mode is gone, swap these
+ // statements so we visit LHS before RHS again.
rhs := r.exprList()
+ names, lhs := r.assignList()
if len(rhs) == 0 {
for _, name := range names {
@@ -1220,8 +1214,12 @@
if r.bool() {
pos := r.pos()
- names, lhs := r.assignList()
+
+ // TODO(mdempsky): After quirks mode is gone, swap these
+ // statements so we read LHS before X again.
x := r.expr()
+ names, lhs := r.assignList()
+
body := r.blockStmt()
r.closeAnotherScope()
@@ -1567,7 +1565,7 @@
r.setType(cv, outer.Type())
}
- r.addBody(fn)
+ r.addBody(fn, r.implicits)
return fn.OClosure
}
@@ -1772,8 +1770,9 @@
r.inlTreeIndex = inlIndex
r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
- for _, cv := range r.inlFunc.ClosureVars {
- r.locals = append(r.locals, cv.Outer)
+ r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
+ for i, cv := range r.inlFunc.ClosureVars {
+ r.closureVars[i] = cv.Outer
}
r.funcargs(fn)
@@ -2015,3 +2014,184 @@
})
return used
}
+
+// @@@ Method wrappers
+
+// needWrapperTypes lists types for which we may need to generate
+// method wrappers.
+var needWrapperTypes []*types.Type
+
+func (r *reader) needWrapper(typ *types.Type) *types.Type {
+ // TODO(mdempsky): Be more judicious about generating wrappers.
+ // For now, generating all possible wrappers is simple and correct,
+ // but potentially wastes a lot of time/space.
+
+ if typ.IsPtr() {
+ base.Fatalf("bad pointer type: %v", typ)
+ }
+
+ needWrapperTypes = append(needWrapperTypes, typ)
+ return typ
+}
+
+func (r *reader) wrapTypes(target *ir.Package) {
+ // always generate a wrapper for error.Error (#29304)
+ r.needWrapper(types.ErrorType)
+
+ seen := make(map[string]*types.Type)
+ for _, typ := range needWrapperTypes {
+ if typ.Sym() == nil {
+ key := typ.ShortString()
+ if prev := seen[key]; prev != nil {
+ if !types.Identical(typ, prev) {
+ base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key)
+ }
+ continue
+ }
+ seen[key] = typ
+ }
+
+ r.wrapType(typ, target)
+ }
+
+ needWrapperTypes = nil
+}
+
+func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
+ if !typ.IsInterface() {
+ typecheck.CalcMethods(typ)
+ }
+ for _, meth := range typ.AllMethods().Slice() {
+ if meth.Sym.IsBlank() || !meth.IsMethod() {
+ base.FatalfAt(meth.Pos, "invalid method: %v", meth)
+ }
+
+ r.methodWrapper(0, typ, meth, target)
+
+ // For non-interface types, we also want *T wrappers.
+ if !typ.IsInterface() {
+ r.methodWrapper(1, typ, meth, target)
+
+ // For not-in-heap types, *T is a scalar, not pointer shaped,
+ // so the interface wrappers use **T.
+ if typ.NotInHeap() {
+ r.methodWrapper(2, typ, meth, target)
+ }
+ }
+ }
+}
+
+func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) {
+ wrapper := tbase
+ for i := 0; i < derefs; i++ {
+ wrapper = types.NewPtr(wrapper)
+ }
+
+ sym := ir.MethodSym(wrapper, method.Sym)
+ assert(!sym.Siggen())
+ sym.SetSiggen(true)
+
+ wrappee := method.Type.Recv().Type
+ if types.Identical(wrapper, wrappee) ||
+ !types.IsMethodApplicable(wrapper, method) ||
+ !reflectdata.NeedEmit(tbase) {
+ return
+ }
+
+ // TODO(mdempsky): Use method.Pos instead?
+ pos := base.AutogeneratedPos
+
+ fn := ir.NewFunc(pos)
+ fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
+ fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
+
+ fn.Nname = ir.NewNameAt(pos, sym)
+ ir.MarkFunc(fn.Nname)
+ fn.Nname.Func = fn
+ fn.Nname.Defn = fn
+
+ sig := newWrapperType(wrapper, method.Type)
+ r.setType(fn.Nname, sig)
+
+ // TODO(mdempsky): De-duplicate with similar logic in funcargs.
+ defParams := func(class ir.Class, params ...*types.Field) {
+ for _, param := range params {
+ name := ir.NewNameAt(param.Pos, param.Sym)
+ name.Class = class
+ r.setType(name, param.Type)
+
+ name.Curfn = fn
+ fn.Dcl = append(fn.Dcl, name)
+
+ param.Nname = name
+ }
+ }
+
+ defParams(ir.PPARAM, sig.Recv())
+ defParams(ir.PPARAM, sig.Params().FieldSlice()...)
+ defParams(ir.PPARAMOUT, sig.Results().FieldSlice()...)
+
+ var recv ir.Node = sig.Recv().Nname.(*ir.Name)
+
+ // For simple *T wrappers around T methods, panicwrap produces a
+ // nicer panic message.
+ if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
+ cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
+ then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
+ fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
+ }
+
+ // Add implicit derefs, as necessary. typecheck will add one deref,
+ // but not-in-heap types will need another for their **T wrappers.
+ for i := 0; i < derefs; i++ {
+ recv = Implicit(ir.NewStarExpr(pos, recv))
+ }
+
+ args := make([]ir.Node, sig.NumParams())
+ for i, param := range sig.Params().FieldSlice() {
+ args[i] = param.Nname.(*ir.Name)
+ }
+
+ fn.Body.Append(newTailCall(pos, method, recv, args))
+
+ target.Decls = append(target.Decls, fn)
+}
+
+// newWrapperType returns a copy of the given signature type, but with
+// the receiver parameter type substituted with wrapper.
+func newWrapperType(wrapper, sig *types.Type) *types.Type {
+ clone := func(params []*types.Field) []*types.Field {
+ res := make([]*types.Field, len(params))
+ for i, param := range params {
+ sym := param.Sym
+ if sym == nil || sym.Name == "_" {
+ sym = typecheck.LookupNum(".anon", i)
+ }
+ res[i] = types.NewField(param.Pos, sym, param.Type)
+ res[i].SetIsDDD(param.IsDDD())
+ }
+ return res
+ }
+
+ recv := types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), wrapper)
+ params := clone(sig.Params().FieldSlice())
+ results := clone(sig.Results().FieldSlice())
+
+ return types.NewSignature(types.NoPkg, recv, nil, params, results)
+}
+
+func newTailCall(pos src.XPos, method *types.Field, recv ir.Node, args []ir.Node) ir.Node {
+ // TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
+ // Not urgent though, because tail calls are currently incompatible with regabi anyway.
+
+ call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args)
+ call.IsDDD = method.Type.IsVariadic()
+
+ if method.Type.NumResults() == 0 {
+ return call
+ }
+
+ ret := ir.NewReturnStmt(pos, nil)
+ ret.Results = []ir.Node{call}
+ return ret
+}
diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go
index 7a1bb88..292fd13 100644
--- a/src/cmd/compile/internal/noder/unified.go
+++ b/src/cmd/compile/internal/noder/unified.go
@@ -74,6 +74,8 @@
if !quirksMode() {
writeNewExportFunc = writeNewExport
+ } else if base.Flag.G != 0 {
+ base.Errorf("cannot use -G and -d=quirksmode together")
}
newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
@@ -126,6 +128,11 @@
}
todoBodies = nil
+ if !quirksMode() {
+ // TODO(mdempsky): Investigate generating wrappers in quirks mode too.
+ r.wrapTypes(target)
+ }
+
// Don't use range--typecheck can add closures to Target.Decls.
for i := 0; i < len(target.Decls); i++ {
target.Decls[i] = typecheck.Stmt(target.Decls[i])
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 889a96e..0496910 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -97,7 +97,10 @@
explicitIdx map[*types2.TypeParam]int
// variables declared within this function
- localsIdx map[types2.Object]int
+ localsIdx map[*types2.Var]int
+
+ closureVars []posObj
+ closureVarsIdx map[*types2.Var]int
}
func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer {
@@ -626,11 +629,15 @@
}
}
+ sig, block := obj.Type().(*types2.Signature), decl.Body
+ body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.explicitIdx)
+ assert(len(closureVars) == 0)
+
w.sync(syncFuncExt)
w.pragmaFlag(pragma)
w.linkname(obj)
w.bool(false) // stub extension
- w.addBody(obj.Type().(*types2.Signature), decl.Body, make(map[types2.Object]int))
+ w.reloc(relocBody, body)
w.sync(syncEOF)
}
@@ -665,41 +672,9 @@
// @@@ Function bodies
-func (w *writer) implicitTypes() map[*types2.TypeParam]int {
- w.sync(syncImplicitTypes)
-
- // TODO(mdempsky): Theoretically, I think at this point we want to
- // extend the implicit type parameters list with any new explicit
- // type parameters.
- //
- // However, I believe that's moot: declared functions and methods
- // have explicit type parameters, but are always declared at package
- // scope (which has no implicit type parameters); and function
- // literals can appear within a type-parameterized function (i.e.,
- // implicit type parameters), but cannot have explicit type
- // parameters of their own.
- //
- // So I think it's safe to just use whichever is non-empty.
- implicitIdx := w.implicitIdx
- if len(implicitIdx) == 0 {
- implicitIdx = w.explicitIdx
- } else {
- assert(len(w.explicitIdx) == 0)
- }
- return implicitIdx
-}
-
-func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsIdx map[types2.Object]int) {
- w.sync(syncAddBody)
-
- implicits := w.implicitTypes()
- w.reloc(relocBody, w.p.bodyIdx(w.p.curpkg, sig, block, implicits, localsIdx))
-}
-
-func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int, localsIdx map[types2.Object]int) int {
+func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int) (idx int, closureVars []posObj) {
w := pw.newWriter(relocBody, syncFuncBody)
w.implicitIdx = implicitIdx
- w.localsIdx = localsIdx
w.funcargs(sig)
if w.bool(block != nil) {
@@ -707,7 +682,7 @@
w.pos(block.Rbrace)
}
- return w.flush()
+ return w.flush(), w.closureVars
}
func (w *writer) funcargs(sig *types2.Signature) {
@@ -730,19 +705,35 @@
}
}
-func (w *writer) addLocal(obj types2.Object) {
+func (w *writer) addLocal(obj *types2.Var) {
w.sync(syncAddLocal)
idx := len(w.localsIdx)
if enableSync {
w.int(idx)
}
+ if w.localsIdx == nil {
+ w.localsIdx = make(map[*types2.Var]int)
+ }
w.localsIdx[obj] = idx
}
-func (w *writer) useLocal(obj types2.Object) {
+func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) {
w.sync(syncUseObjLocal)
- idx, ok := w.localsIdx[obj]
- assert(ok)
+
+ if idx, ok := w.localsIdx[obj]; w.bool(ok) {
+ w.len(idx)
+ return
+ }
+
+ idx, ok := w.closureVarsIdx[obj]
+ if !ok {
+ if w.closureVarsIdx == nil {
+ w.closureVarsIdx = make(map[*types2.Var]int)
+ }
+ idx = len(w.closureVars)
+ w.closureVars = append(w.closureVars, posObj{pos, obj})
+ w.closureVarsIdx[obj] = idx
+ }
w.len(idx)
}
@@ -806,8 +797,8 @@
default:
w.code(stmtAssign)
w.pos(stmt)
- w.assignList(stmt.Lhs)
w.exprList(stmt.Rhs)
+ w.assignList(stmt.Lhs)
}
case *syntax.BlockStmt:
@@ -877,6 +868,8 @@
for _, expr := range exprs {
if name, ok := expr.(*syntax.Name); ok && name.Value != "_" {
if obj, ok := w.p.info.Defs[name]; ok {
+ obj := obj.(*types2.Var)
+
w.bool(true)
w.pos(obj)
w.localIdent(obj)
@@ -923,16 +916,16 @@
for i, name := range decl.NameList {
w.code(stmtAssign)
w.pos(decl)
- w.assignList(name)
w.exprList(values[i])
+ w.assignList(name)
}
break
}
w.code(stmtAssign)
w.pos(decl)
- w.assignList(namesAsExpr(decl.NameList))
w.exprList(decl.Values)
+ w.assignList(namesAsExpr(decl.NameList))
}
}
@@ -949,8 +942,8 @@
if rang, ok := stmt.Init.(*syntax.RangeClause); w.bool(ok) {
w.pos(rang)
- w.assignList(rang.Lhs)
w.expr(rang.X)
+ w.assignList(rang.Lhs)
} else {
w.pos(stmt)
w.stmt(stmt.Init)
@@ -1092,15 +1085,17 @@
}
if obj != nil {
- if _, ok := w.localsIdx[obj]; ok {
- assert(len(targs) == 0)
- w.code(exprLocal)
- w.useLocal(obj)
+ if isGlobal(obj) {
+ w.code(exprName)
+ w.obj(obj, targs)
return
}
- w.code(exprName)
- w.obj(obj, targs)
+ obj := obj.(*types2.Var)
+ assert(len(targs) == 0)
+
+ w.code(exprLocal)
+ w.useLocal(expr.Pos(), obj)
return
}
@@ -1248,106 +1243,24 @@
w.pos(expr.Type) // for QuirksMode
w.signature(sig)
- closureVars, localsIdx := w.captureVars(expr)
+ block := expr.Body
+ body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.implicitIdx)
+
w.len(len(closureVars))
- for _, closureVar := range closureVars {
- w.pos(closureVar.pos)
- w.useLocal(closureVar.obj)
+ for _, cv := range closureVars {
+ w.pos(cv.pos)
+ if quirksMode() {
+ cv.pos = expr.Body.Rbrace
+ }
+ w.useLocal(cv.pos, cv.obj)
}
- w.addBody(sig, expr.Body, localsIdx)
+ w.reloc(relocBody, body)
}
type posObj struct {
pos syntax.Pos
- obj types2.Object
-}
-
-// captureVars returns the free variables used by the given function
-// literal.
-func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, localsIdx map[types2.Object]int) {
- scope, ok := w.p.info.Scopes[expr.Type]
- assert(ok)
-
- localsIdx = make(map[types2.Object]int)
-
- // TODO(mdempsky): This code needs to be cleaned up (e.g., to avoid
- // traversing nested function literals multiple times). This will be
- // easier after we drop quirks mode.
-
- var rbracePos syntax.Pos
-
- var visitor func(n syntax.Node) bool
- visitor = func(n syntax.Node) bool {
-
- // Constant expressions don't count towards capturing.
- if n, ok := n.(syntax.Expr); ok {
- if tv, ok := w.p.info.Types[n]; ok && tv.Value != nil {
- return true
- }
- }
-
- switch n := n.(type) {
- case *syntax.Name:
- if obj, ok := w.p.info.Uses[n].(*types2.Var); ok && !obj.IsField() && obj.Pkg() == w.p.curpkg && obj.Parent() != obj.Pkg().Scope() {
- // Found a local variable. See if it chains up to scope.
- parent := obj.Parent()
- for {
- if parent == scope {
- break
- }
- if parent == obj.Pkg().Scope() {
- if _, present := localsIdx[obj]; !present {
- pos := rbracePos
- if pos == (syntax.Pos{}) {
- pos = n.Pos()
- }
-
- idx := len(closureVars)
- closureVars = append(closureVars, posObj{pos, obj})
- localsIdx[obj] = idx
- }
- break
- }
- parent = parent.Parent()
- }
- }
-
- case *syntax.FuncLit:
- // Quirk: typecheck uses the rbrace position position of the
- // function literal as the position of the intermediary capture.
- if quirksMode() && rbracePos == (syntax.Pos{}) {
- rbracePos = n.Body.Rbrace
- syntax.Crawl(n.Body, visitor)
- rbracePos = syntax.Pos{}
- return true
- }
-
- case *syntax.AssignStmt:
- // Quirk: typecheck visits (and thus captures) the RHS of
- // assignment statements before the LHS.
- if quirksMode() && (n.Op == 0 || n.Op == syntax.Def) {
- syntax.Crawl(n.Rhs, visitor)
- syntax.Crawl(n.Lhs, visitor)
- return true
- }
- case *syntax.RangeClause:
- // Quirk: Similarly, it visits the expression to be iterated
- // over before the iteration variables.
- if quirksMode() {
- syntax.Crawl(n.X, visitor)
- if n.Lhs != nil {
- syntax.Crawl(n.Lhs, visitor)
- }
- return true
- }
- }
-
- return false
- }
- syntax.Crawl(expr.Body, visitor)
-
- return
+ obj *types2.Var
}
func (w *writer) exprList(expr syntax.Expr) {
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 8378fab..8421e36 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -927,29 +927,27 @@
if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
tbase = t.Elem()
}
+ if tbase.Kind() == types.TFORW {
+ base.Fatalf("unresolved defined type: %v", tbase)
+ }
+
dupok := 0
- if tbase.Sym() == nil {
+ if tbase.Sym() == nil { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
dupok = obj.DUPOK
}
- if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
- // Named types from other files are defined only by those files.
- // However, as an exception, we can write out instantiated types
- // in the local package, even if they may be marked as part of
- // another package (the package of their base generic type).
- if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg &&
- !tbase.IsFullyInstantiated() {
- if i := typecheck.BaseTypeIndex(t); i >= 0 {
- lsym.Pkg = tbase.Sym().Pkg.Prefix
- lsym.SymIdx = int32(i)
- lsym.Set(obj.AttrIndexed, true)
- }
- return lsym
+ if !NeedEmit(tbase) {
+ if i := typecheck.BaseTypeIndex(t); i >= 0 {
+ lsym.Pkg = tbase.Sym().Pkg.Prefix
+ lsym.SymIdx = int32(i)
+ lsym.Set(obj.AttrIndexed, true)
}
- // TODO(mdempsky): Investigate whether this can happen.
- if tbase.Kind() == types.TFORW {
- return lsym
- }
+
+ // TODO(mdempsky): Investigate whether this still happens.
+ // If we know we don't need to emit code for a type,
+ // we should have a link-symbol index for it.
+ // See also TODO in NeedEmit.
+ return lsym
}
ot := 0
@@ -1678,6 +1676,44 @@
}
}
+// NeedEmit reports whether typ is a type that we need to emit code
+// for (e.g., runtime type descriptors, method wrappers).
+func NeedEmit(typ *types.Type) bool {
+ // TODO(mdempsky): Export data should keep track of which anonymous
+ // and instantiated types were emitted, so at least downstream
+ // packages can skip re-emitting them.
+ //
+ // Perhaps we can just generalize the linker-symbol indexing to
+ // track the index of arbitrary types, not just defined types, and
+ // use its presence to detect this. The same idea would work for
+ // instantiated generic functions too.
+
+ switch sym := typ.Sym(); {
+ case sym == nil:
+ // Anonymous type; possibly never seen before or ever again.
+ // Need to emit to be safe (however, see TODO above).
+ return true
+
+ case sym.Pkg == types.LocalPkg:
+ // Local defined type; our responsibility.
+ return true
+
+ case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
+ // Package runtime is responsible for including code for builtin
+ // types (predeclared and package unsafe).
+ return true
+
+ case typ.IsFullyInstantiated():
+ // Instantiated type; possibly instantiated with unique type arguments.
+ // Need to emit to be safe (however, see TODO above).
+ return true
+
+ default:
+ // Should have been emitted by an imported package.
+ return false
+ }
+}
+
// Generate a wrapper function to convert from
// a receiver of type T to a receiver of type U.
// That is,
@@ -1724,10 +1760,6 @@
// TODO: check that we do the right thing when method is an interface method.
generic = true
}
- if base.Debug.Unified != 0 {
- // TODO(mdempsky): Support dictionaries for unified IR.
- generic = false
- }
newnam := ir.MethodSym(rcvr, method.Sym)
lsym := newnam.Linksym()
if newnam.Siggen() {
@@ -1735,28 +1767,17 @@
}
newnam.SetSiggen(true)
+ // Except in quirks mode, unified IR creates its own wrappers.
+ // Complain loudly if it missed any.
+ if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
+ base.FatalfAt(method.Pos, "missing wrapper for %+v (%+v, %v) / %+v / %+v", rcvr, orig, types.IsDirectIface(orig), method.Sym, newnam)
+ }
+
if !generic && types.Identical(rcvr, method.Type.Recv().Type) {
return lsym
}
- // imported reports whether typ is a defined type that was declared
- // in an imported package, and therefore must have been compiled in
- // that package.
- importedType := func(typ *types.Type) bool {
- return typ.Sym() != nil && typ.Sym().Pkg != types.LocalPkg &&
-
- // Exception: need wrapper for error.Error (#29304).
- // TODO(mdempsky): Put this in package runtime, like we do for
- // the type descriptors for predeclared types.
- typ != types.ErrorType &&
-
- // Exception: parameterized types may have been instantiated
- // with new type arguments, so we don't assume they've been
- // compiled before.
- !typ.IsFullyInstantiated()
- }
-
- if importedType(rcvr) || rcvr.IsPtr() && importedType(rcvr.Elem()) {
+ if !NeedEmit(rcvr) || rcvr.IsPtr() && !NeedEmit(rcvr.Elem()) {
return lsym
}
diff --git a/test/fixedbugs/issue46903.go b/test/fixedbugs/issue46903.go
new file mode 100644
index 0000000..3237a58
--- /dev/null
+++ b/test/fixedbugs/issue46903.go
@@ -0,0 +1,32 @@
+// run
+//go:build goexperiment.unified
+// +build goexperiment.unified
+
+// TODO(mdempsky): Enable test unconditionally. This test should pass
+// for non-unified mode too.
+
+// Copyright 2021 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.
+
+package main
+
+//go:notinheap
+type A struct{ B }
+type B struct{ x byte }
+type I interface{ M() *B }
+
+func (p *B) M() *B { return p }
+
+var (
+ a A
+ i I = &a
+)
+
+func main() {
+ got, want := i.M(), &a.B
+ if got != want {
+ println(got, "!=", want)
+ panic("FAIL")
+ }
+}
diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go
index d70f94f..de1140b 100644
--- a/test/typeparam/issue44688.go
+++ b/test/typeparam/issue44688.go
@@ -1,6 +1,4 @@
// run -gcflags=-G=3
-//go:build goexperiment.unified
-// +build !goexperiment.unified
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style