]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/typecheck/func.go
[dev.typeparams] all: merge master (4711bf3) into dev.typeparams
[gostls13.git] / src / cmd / compile / internal / typecheck / func.go
index fbcc784627d6ce8d64bb17eab49b7a679af10ab5..d0aad5ac0788e00a836968a18e85932dd7c9696d 100644 (file)
@@ -8,28 +8,29 @@ import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
+       "cmd/internal/src"
 
        "fmt"
        "go/constant"
        "go/token"
 )
 
-// package all the arguments that match a ... T parameter into a []T.
-func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node {
+// MakeDotArgs package all the arguments that match a ... T parameter into a []T.
+func MakeDotArgs(pos src.XPos, typ *types.Type, args []ir.Node) ir.Node {
        var n ir.Node
        if len(args) == 0 {
-               n = NodNil()
+               n = ir.NewNilExpr(pos)
                n.SetType(typ)
        } else {
-               lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
-               lit.List.Append(args...)
+               args = append([]ir.Node(nil), args...)
+               lit := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(typ), args)
                lit.SetImplicit(true)
                n = lit
        }
 
        n = Expr(n)
        if n.Type() == nil {
-               base.Fatalf("mkdotargslice: typecheck failed")
+               base.FatalfAt(pos, "mkdotargslice: typecheck failed")
        }
        return n
 }
@@ -47,7 +48,7 @@ func FixVariadicCall(call *ir.CallExpr) {
 
        args := call.Args
        extra := args[vi:]
-       slice := MakeDotArgs(vt, extra)
+       slice := MakeDotArgs(call.Pos(), vt, extra)
        for i := range extra {
                extra[i] = nil // allow GC
        }
@@ -56,6 +57,25 @@ func FixVariadicCall(call *ir.CallExpr) {
        call.IsDDD = true
 }
 
+// FixMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
+func FixMethodCall(call *ir.CallExpr) {
+       if call.X.Op() != ir.ODOTMETH {
+               return
+       }
+
+       dot := call.X.(*ir.SelectorExpr)
+
+       fn := Expr(ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym))
+
+       args := make([]ir.Node, 1+len(call.Args))
+       args[0] = dot.X
+       copy(args[1:], call.Args)
+
+       call.SetOp(ir.OCALLFUNC)
+       call.X = fn
+       call.Args = args
+}
+
 // ClosureType returns the struct type used to hold all the information
 // needed in the closure for clo (clo must be a OCLOSURE node).
 // The address of a variable of the returned type can be cast to a func.
@@ -73,8 +93,25 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
        // The information appears in the binary in the form of type descriptors;
        // the struct is unnamed so that closures in multiple packages with the
        // same struct type can share the descriptor.
+
+       // Make sure the .F field is in the same package as the rest of the
+       // fields. This deals with closures in instantiated functions, which are
+       // compiled as if from the source package of the generic function.
+       var pkg *types.Pkg
+       if len(clo.Func.ClosureVars) == 0 {
+               pkg = types.LocalPkg
+       } else {
+               for _, v := range clo.Func.ClosureVars {
+                       if pkg == nil {
+                               pkg = v.Sym().Pkg
+                       } else if pkg != v.Sym().Pkg {
+                               base.Fatalf("Closure variables from multiple packages")
+                       }
+               }
+       }
+
        fields := []*types.Field{
-               types.NewField(base.Pos, Lookup(".F"), types.Types[types.TUINTPTR]),
+               types.NewField(base.Pos, pkg.Lookup(".F"), types.Types[types.TUINTPTR]),
        }
        for _, v := range clo.Func.ClosureVars {
                typ := v.Type()
@@ -89,7 +126,7 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
 }
 
 // PartialCallType returns the struct type used to hold all the information
-// needed in the closure for n (n must be a OCALLPART node).
+// needed in the closure for n (n must be a OMETHVALUE node).
 // The address of a variable of the returned type can be cast to a func.
 func PartialCallType(n *ir.SelectorExpr) *types.Type {
        t := types.NewStruct(types.NoPkg, []*types.Field{
@@ -181,121 +218,24 @@ func fnpkg(fn *ir.Name) *types.Pkg {
        return fn.Sym().Pkg
 }
 
-// ClosureName generates a new unique name for a closure within
-// outerfunc.
-func ClosureName(outerfunc *ir.Func) *types.Sym {
-       outer := "glob."
-       prefix := "func"
-       gen := &globClosgen
-
-       if outerfunc != nil {
-               if outerfunc.OClosure != nil {
-                       prefix = ""
-               }
-
-               outer = ir.FuncName(outerfunc)
-
-               // There may be multiple functions named "_". In those
-               // cases, we can't use their individual Closgens as it
-               // would lead to name clashes.
-               if !ir.IsBlank(outerfunc.Nname) {
-                       gen = &outerfunc.Closgen
-               }
-       }
-
-       *gen++
-       return Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
-}
-
-// globClosgen is like Func.Closgen, but for the global scope.
-var globClosgen int32
-
-// MethodValueWrapper returns the DCLFUNC node representing the
-// wrapper function (*-fm) needed for the given method value. If the
-// wrapper function hasn't already been created yet, it's created and
-// added to Target.Decls.
-//
-// TODO(mdempsky): Move into walk. This isn't part of type checking.
-func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
-       if dot.Op() != ir.OCALLPART {
-               base.Fatalf("MethodValueWrapper: unexpected %v (%v)", dot, dot.Op())
-       }
-
-       t0 := dot.Type()
-       meth := dot.Sel
-       rcvrtype := dot.X.Type()
-       sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
-
-       if sym.Uniq() {
-               return sym.Def.(*ir.Func)
-       }
-       sym.SetUniq(true)
-
-       savecurfn := ir.CurFunc
-       saveLineNo := base.Pos
-       ir.CurFunc = nil
-
-       // Set line number equal to the line number where the method is declared.
-       if pos := dot.Selection.Pos; pos.IsKnown() {
-               base.Pos = pos
-       }
-       // Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
-       // the method is implicitly declared. The Error method of the
-       // built-in error type is one such method.  We leave the line
-       // number at the use of the method expression in this
-       // case. See issue 29389.
-
-       tfn := ir.NewFuncType(base.Pos, nil,
-               NewFuncParams(t0.Params(), true),
-               NewFuncParams(t0.Results(), false))
-
-       fn := DeclFunc(sym, tfn)
-       fn.SetDupok(true)
-       fn.SetNeedctxt(true)
-       fn.SetWrapper(true)
-
-       // Declare and initialize variable holding receiver.
-       ptr := ir.NewNameAt(base.Pos, Lookup(".this"))
-       ptr.Class = ir.PAUTOHEAP
-       ptr.SetType(rcvrtype)
-       ptr.Curfn = fn
-       ptr.SetIsClosureVar(true)
-       ptr.SetByval(true)
-       fn.ClosureVars = append(fn.ClosureVars, ptr)
-
-       call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
-       call.Args = ir.ParamNames(tfn.Type())
-       call.IsDDD = tfn.Type().IsVariadic()
-
-       var body ir.Node = call
-       if t0.NumResults() != 0 {
-               ret := ir.NewReturnStmt(base.Pos, nil)
-               ret.Results = []ir.Node{call}
-               body = ret
-       }
-
-       fn.Body = []ir.Node{body}
-       FinishFuncBody()
-
-       Func(fn)
-       // Need to typecheck the body of the just-generated wrapper.
-       // typecheckslice() requires that Curfn is set when processing an ORETURN.
-       ir.CurFunc = fn
-       Stmts(fn.Body)
-       sym.Def = fn
-       Target.Decls = append(Target.Decls, fn)
-       ir.CurFunc = savecurfn
-       base.Pos = saveLineNo
-
-       return fn
-}
-
 // tcClosure typechecks an OCLOSURE node. It also creates the named
 // function associated with the closure.
 // TODO: This creation of the named function should probably really be done in a
 // separate pass from type-checking.
-func tcClosure(clo *ir.ClosureExpr, top int) {
+func tcClosure(clo *ir.ClosureExpr, top int) ir.Node {
        fn := clo.Func
+
+       // We used to allow IR builders to typecheck the underlying Func
+       // themselves, but that led to too much variety and inconsistency
+       // around who's responsible for naming the function, typechecking
+       // it, or adding it to Target.Decls.
+       //
+       // It's now all or nothing. Callers are still allowed to do these
+       // themselves, but then they assume responsibility for all of them.
+       if fn.Typecheck() == 1 {
+               base.FatalfAt(fn.Pos(), "underlying closure func already typechecked: %v", fn)
+       }
+
        // Set current associated iota value, so iota can be used inside
        // function in ConstSpec, see issue #22344
        if x := getIotaValue(); x >= 0 {
@@ -304,30 +244,14 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
 
        fn.SetClosureCalled(top&ctxCallee != 0)
 
-       // Do not typecheck fn twice, otherwise, we will end up pushing
-       // fn to Target.Decls multiple times, causing InitLSym called twice.
-       // See #30709
-       if fn.Typecheck() == 1 {
-               clo.SetType(fn.Type())
-               return
-       }
-
-       // Don't give a name and add to Target.Decls if we are typechecking an inlined
-       // body in ImportedBody(), since we only want to create the named function
-       // when the closure is actually inlined (and then we force a typecheck
-       // explicitly in (*inlsubst).node()).
-       if !inTypeCheckInl {
-               fn.Nname.SetSym(ClosureName(ir.CurFunc))
-               ir.MarkFunc(fn.Nname)
-       }
+       ir.NameClosure(clo, ir.CurFunc)
        Func(fn)
-       clo.SetType(fn.Type())
 
        // Type check the body now, but only if we're inside a function.
        // At top level (in a variable initialization: curfn==nil) we're not
        // ready to type check code yet; we'll check it later, because the
        // underlying closure function we create is added to Target.Decls.
-       if ir.CurFunc != nil && clo.Type() != nil {
+       if ir.CurFunc != nil {
                oldfn := ir.CurFunc
                ir.CurFunc = fn
                Stmts(fn.Body)
@@ -353,14 +277,17 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
        }
        fn.ClosureVars = fn.ClosureVars[:out]
 
-       if base.Flag.W > 1 {
-               s := fmt.Sprintf("New closure func: %s", ir.FuncName(fn))
-               ir.Dump(s, fn)
-       }
-       if !inTypeCheckInl {
-               // Add function to Target.Decls once only when we give it a name
-               Target.Decls = append(Target.Decls, fn)
+       clo.SetType(fn.Type())
+
+       target := Target
+       if inTypeCheckInl {
+               // We're typechecking an imported function, so it's not actually
+               // part of Target. Skip adding it to Target.Decls so we don't
+               // compile it again.
+               target = nil
        }
+
+       return ir.UseClosure(clo, target)
 }
 
 // type check function definition
@@ -509,6 +436,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
        }
 
        typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.X) })
+       FixMethodCall(n)
        if t.NumResults() == 0 {
                return n
        }
@@ -979,6 +907,21 @@ func tcRecover(n *ir.CallExpr) ir.Node {
        return n
 }
 
+// tcRecoverFP typechecks an ORECOVERFP node.
+func tcRecoverFP(n *ir.CallExpr) ir.Node {
+       if len(n.Args) != 1 {
+               base.FatalfAt(n.Pos(), "wrong number of arguments: %v", n)
+       }
+
+       n.Args[0] = Expr(n.Args[0])
+       if !n.Args[0].Type().IsPtrShaped() {
+               base.FatalfAt(n.Pos(), "%L is not pointer shaped", n.Args[0])
+       }
+
+       n.SetType(types.Types[types.TINTER])
+       return n
+}
+
 // tcUnsafeAdd typechecks an OUNSAFEADD node.
 func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
        if !types.AllowsGoVersion(curpkg(), 1, 17) {