blob: 6c8ed4af97299bc43eef6d4f8caa8b5f55659e12 [file] [log] [blame]
// 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 noder
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/compile/internal/types2"
"cmd/internal/src"
)
func (g *irgen) def(name *syntax.Name) (*ir.Name, types2.Object) {
obj, ok := g.info.Defs[name]
if !ok {
base.FatalfAt(g.pos(name), "unknown name %v", name)
}
return g.obj(obj), obj
}
// use returns the Name node associated with the use of name. The returned node
// will have the correct type and be marked as typechecked.
func (g *irgen) use(name *syntax.Name) *ir.Name {
obj2, ok := g.info.Uses[name]
if !ok {
base.FatalfAt(g.pos(name), "unknown name %v", name)
}
obj := ir.CaptureName(g.pos(obj2), ir.CurFunc, g.obj(obj2))
if obj.Defn != nil && obj.Defn.Op() == ir.ONAME {
// If CaptureName created a closure variable, then transfer the
// type of the captured name to the new closure variable.
obj.SetTypecheck(1)
obj.SetType(obj.Defn.Type())
}
return obj
}
// obj returns the Name that represents the given object. If no such Name exists
// yet, it will be implicitly created. The returned node will have the correct
// type and be marked as typechecked.
//
// For objects declared at function scope, ir.CurFunc must already be
// set to the respective function when the Name is created.
func (g *irgen) obj(obj types2.Object) *ir.Name {
// For imported objects, we use iimport directly instead of mapping
// the types2 representation.
if obj.Pkg() != g.self {
sym := g.sym(obj)
if sym.Def != nil {
return sym.Def.(*ir.Name)
}
n := typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
if n, ok := n.(*ir.Name); ok {
n.SetTypecheck(1)
return n
}
base.FatalfAt(g.pos(obj), "failed to resolve %v", obj)
}
if name, ok := g.objs[obj]; ok {
return name // previously mapped
}
var name *ir.Name
pos := g.pos(obj)
class := typecheck.DeclContext
if obj.Parent() == g.self.Scope() {
class = ir.PEXTERN // forward reference to package-block declaration
}
// "You are in a maze of twisting little passages, all different."
switch obj := obj.(type) {
case *types2.Const:
name = g.objCommon(pos, ir.OLITERAL, g.sym(obj), class, g.typ(obj.Type()))
case *types2.Func:
sig := obj.Type().(*types2.Signature)
var sym *types.Sym
var typ *types.Type
if recv := sig.Recv(); recv == nil {
if obj.Name() == "init" {
sym = renameinit()
} else {
sym = g.sym(obj)
}
typ = g.typ(sig)
} else {
sym = g.selector(obj)
if !sym.IsBlank() {
sym = ir.MethodSym(g.typ(recv.Type()), sym)
}
typ = g.signature(g.param(recv), sig)
}
name = g.objCommon(pos, ir.ONAME, sym, ir.PFUNC, typ)
case *types2.TypeName:
if obj.IsAlias() {
name = g.objCommon(pos, ir.OTYPE, g.sym(obj), class, g.typ(obj.Type()))
} else {
name = ir.NewDeclNameAt(pos, ir.OTYPE, g.sym(obj))
g.objFinish(name, class, types.NewNamed(name))
}
case *types2.Var:
var sym *types.Sym
if class == ir.PPARAMOUT {
// Backend needs names for result parameters,
// even if they're anonymous or blank.
switch obj.Name() {
case "":
sym = typecheck.LookupNum("~r", len(ir.CurFunc.Dcl)) // 'r' for "result"
case "_":
sym = typecheck.LookupNum("~b", len(ir.CurFunc.Dcl)) // 'b' for "blank"
}
}
if sym == nil {
sym = g.sym(obj)
}
name = g.objCommon(pos, ir.ONAME, sym, class, g.typ(obj.Type()))
default:
g.unhandled("object", obj)
}
g.objs[obj] = name
name.SetTypecheck(1)
return name
}
func (g *irgen) objCommon(pos src.XPos, op ir.Op, sym *types.Sym, class ir.Class, typ *types.Type) *ir.Name {
name := ir.NewDeclNameAt(pos, op, sym)
g.objFinish(name, class, typ)
return name
}
func (g *irgen) objFinish(name *ir.Name, class ir.Class, typ *types.Type) {
sym := name.Sym()
name.SetType(typ)
name.Class = class
if name.Class == ir.PFUNC {
sym.SetFunc(true)
}
// We already know name's type, but typecheck is really eager to try
// recomputing it later. This appears to prevent that at least.
name.Ntype = ir.TypeNode(typ)
name.SetTypecheck(1)
name.SetWalkdef(1)
if ir.IsBlank(name) {
return
}
switch class {
case ir.PEXTERN:
g.target.Externs = append(g.target.Externs, name)
fallthrough
case ir.PFUNC:
sym.Def = name
if name.Class == ir.PFUNC && name.Type().Recv() != nil {
break // methods are exported with their receiver type
}
if types.IsExported(sym.Name) {
if name.Class == ir.PFUNC && name.Type().NumTParams() > 0 {
base.FatalfAt(name.Pos(), "Cannot export a generic function (yet): %v", name)
}
typecheck.Export(name)
}
if base.Flag.AsmHdr != "" && !name.Sym().Asm() {
name.Sym().SetAsm(true)
g.target.Asms = append(g.target.Asms, name)
}
default:
// Function-scoped declaration.
name.Curfn = ir.CurFunc
if name.Op() == ir.ONAME {
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, name)
}
}
}