aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/noder/helpers.go25
-rw-r--r--src/cmd/compile/internal/noder/stencil.go41
-rw-r--r--src/cmd/compile/internal/noder/transform.go293
-rw-r--r--src/cmd/compile/internal/typecheck/expr.go10
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go24
5 files changed, 342 insertions, 51 deletions
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 82428daa4a..9ebf17aae6 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -81,8 +81,8 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) ir.Node {
n.SetTypecheck(3)
return n
}
- n1 := transformAdd(n)
- return typed(typ, n1)
+ typed(typ, n)
+ return transformAdd(n)
default:
return typed(x.Type(), ir.NewBinaryExpr(pos, op, x, y))
}
@@ -99,9 +99,8 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
// the type.
return typed(typ, n)
}
- n1 := transformConvCall(n)
- n1.SetTypecheck(1)
- return n1
+ typed(typ, n)
+ return transformConvCall(n)
}
if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
@@ -133,12 +132,8 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
}
}
- switch fun.BuiltinOp {
- case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN:
- return typecheck.Stmt(n)
- default:
- return typecheck.Expr(n)
- }
+ typed(typ, n)
+ return transformBuiltin(n)
}
// Add information, now that we know that fun is actually being called.
@@ -176,8 +171,8 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
if fun.Op() != ir.OFUNCINST {
// If no type params, do the normal call transformations. This
// will convert OCALL to OCALLFUNC.
- transformCall(n)
typed(typ, n)
+ transformCall(n)
return n
}
@@ -195,8 +190,9 @@ func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) ir.Node {
n.SetTypecheck(3)
return n
}
+ typed(typ, n)
transformCompare(n)
- return typed(typ, n)
+ return n
}
func Deref(pos src.XPos, x ir.Node) *ir.StarExpr {
@@ -291,8 +287,9 @@ func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) ir.Node {
n.SetTypecheck(3)
return n
}
+ typed(typ, n)
transformSlice(n)
- return typed(typ, n)
+ return n
}
func Unary(pos src.XPos, op ir.Op, x ir.Node) ir.Node {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index ba01f0424b..45864763d4 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -369,12 +369,12 @@ func (subst *subster) node(n ir.Node) ir.Node {
if x.Typecheck() == 3 {
// These are nodes whose transforms were delayed until
// their instantiated type was known.
+ m.SetTypecheck(1)
if typecheck.IsCmp(x.Op()) {
transformCompare(m.(*ir.BinaryExpr))
} else {
switch x.Op() {
- case ir.OSLICE:
- case ir.OSLICE3:
+ case ir.OSLICE, ir.OSLICE3:
transformSlice(m.(*ir.SliceExpr))
case ir.OADD:
@@ -400,7 +400,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
base.Fatalf("Unexpected node with Typecheck() == 3")
}
}
- m.SetTypecheck(1)
}
switch x.Op() {
@@ -421,15 +420,18 @@ func (subst *subster) node(n ir.Node) ir.Node {
}
case ir.OXDOT:
- // A method value/call via a type param will have been left as an
- // OXDOT. When we see this during stenciling, finish the
- // typechecking, now that we have the instantiated receiver type.
- // We need to do this now, since the access/selection to the
- // method for the real type is very different from the selection
- // for the type param.
- m.SetTypecheck(0)
- // m will transform to an OCALLPART
- typecheck.Expr(m)
+ // A method value/call via a type param will have been
+ // left as an OXDOT. When we see this during stenciling,
+ // finish the transformation, now that we have the
+ // instantiated receiver type. We need to do this now,
+ // since the access/selection to the method for the real
+ // type is very different from the selection for the type
+ // param. m will be transformed to an OCALLPART node. It
+ // will be transformed to an ODOTMETH or ODOTINTER node if
+ // we find in the OCALL case below that the method value
+ // is actually called.
+ transformDot(m.(*ir.SelectorExpr), false)
+ m.SetTypecheck(1)
case ir.OCALL:
call := m.(*ir.CallExpr)
@@ -437,15 +439,12 @@ func (subst *subster) node(n ir.Node) ir.Node {
// Transform the conversion, now that we know the
// type argument.
m = transformConvCall(m.(*ir.CallExpr))
- m.SetTypecheck(1)
} else if call.X.Op() == ir.OCALLPART {
- // Redo the typechecking of OXDOT, now that we
+ // Redo the transformation of OXDOT, now that we
// know the method value is being called. Then
// transform the call.
call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
- call.X.SetTypecheck(0)
- call.X.SetType(nil)
- typecheck.Callee(call.X)
+ transformDot(call.X.(*ir.SelectorExpr), true)
transformCall(call)
} else if call.X.Op() == ir.ODOT || call.X.Op() == ir.ODOTPTR {
// An OXDOT for a generic receiver was resolved to
@@ -456,11 +455,9 @@ func (subst *subster) node(n ir.Node) ir.Node {
} else if name := call.X.Name(); name != nil {
switch name.BuiltinOp {
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND:
- // Call old typechecker (to do any
- // transformations) now that we know the
- // type of the args.
- m.SetTypecheck(0)
- m = typecheck.Expr(m)
+ // Transform these builtins now that we
+ // know the type of the args.
+ m = transformBuiltin(call)
default:
base.FatalfAt(call.Pos(), "Unexpected builtin op")
}
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index e90d374d0f..489a535231 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -11,6 +11,10 @@
// - Setting the actual type of existing nodes (already done based on
// type info from types2)
// - Dealing with untyped constants (which types2 has already resolved)
+//
+// Each of the transformation functions requires that node passed in has its type
+// and typecheck flag set. If the transformation function replaces or adds new
+// nodes, it will set the type and typecheck flag for those new nodes.
package noder
@@ -19,6 +23,7 @@ import (
"cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
+ "fmt"
"go/constant"
)
@@ -27,6 +32,7 @@ import (
// transformAdd transforms an addition operation (currently just addition of
// strings). Corresponds to the "binary operators" case in typecheck.typecheck1.
func transformAdd(n *ir.BinaryExpr) ir.Node {
+ assert(n.Type() != nil && n.Typecheck() == 1)
l := n.X
if l.Type().IsString() {
var add *ir.AddStringExpr
@@ -43,7 +49,7 @@ func transformAdd(n *ir.BinaryExpr) ir.Node {
} else {
add.List.Append(r)
}
- add.SetType(l.Type())
+ typed(l.Type(), add)
return add
}
return n
@@ -74,7 +80,6 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node {
func transformConv(n *ir.ConvExpr) ir.Node {
t := n.X.Type()
op, _ := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type())
- assert(op != ir.OXXX)
n.SetOp(op)
switch n.Op() {
case ir.OCONVNOP:
@@ -103,15 +108,18 @@ func transformConv(n *ir.ConvExpr) ir.Node {
// transformConvCall transforms a conversion call. Corresponds to the OTYPE part of
// typecheck.tcCall.
func transformConvCall(n *ir.CallExpr) ir.Node {
+ assert(n.Type() != nil && n.Typecheck() == 1)
arg := n.Args[0]
n1 := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
- n1.SetType(n.X.Type())
+ typed(n.X.Type(), n1)
return transformConv(n1)
}
// transformCall transforms a normal function/method call. Corresponds to last half
// (non-conversion, non-builtin part) of typecheck.tcCall.
func transformCall(n *ir.CallExpr) {
+ // n.Type() can be nil for calls with no return value
+ assert(n.Typecheck() == 1)
transformArgs(n)
l := n.X
t := l.Type()
@@ -160,6 +168,7 @@ func transformCall(n *ir.CallExpr) {
// equals). Corresponds to the "comparison operators" case in
// typecheck.typecheck1, including tcArith.
func transformCompare(n *ir.BinaryExpr) {
+ assert(n.Type() != nil && n.Typecheck() == 1)
if (n.Op() == ir.OEQ || n.Op() == ir.ONE) && !types.Identical(n.X.Type(), n.Y.Type()) {
// Comparison is okay as long as one side is assignable to the
// other. The only allowed case where the conversion is not CONVNOP is
@@ -214,6 +223,7 @@ func implicitstar(n ir.Node) ir.Node {
// transformIndex transforms an index operation. Corresponds to typecheck.tcIndex.
func transformIndex(n *ir.IndexExpr) {
+ assert(n.Type() != nil && n.Typecheck() == 1)
n.X = implicitstar(n.X)
l := n.X
t := l.Type()
@@ -230,6 +240,7 @@ func transformIndex(n *ir.IndexExpr) {
// transformSlice transforms a slice operation. Corresponds to typecheck.tcSlice.
func transformSlice(n *ir.SliceExpr) {
+ assert(n.Type() != nil && n.Typecheck() == 1)
l := n.X
if l.Type().IsArray() {
addr := typecheck.NodAddr(n.X)
@@ -521,3 +532,279 @@ func transformSelect(sel *ir.SelectStmt) {
func transformAsOp(n *ir.AssignOpStmt) {
transformCheckAssign(n, n.X)
}
+
+// transformDot transforms an OXDOT (or ODOT) or ODOT, ODOTPTR, ODOTMETH,
+// ODOTINTER, or OCALLPART, as appropriate. It adds in extra nodes as needed to
+// access embedded fields. Corresponds to typecheck.tcDot.
+func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
+ assert(n.Type() != nil && n.Typecheck() == 1)
+ if n.Op() == ir.OXDOT {
+ n = typecheck.AddImplicitDots(n)
+ n.SetOp(ir.ODOT)
+ }
+
+ t := n.X.Type()
+
+ if n.X.Op() == ir.OTYPE {
+ return transformMethodExpr(n)
+ }
+
+ if t.IsPtr() && !t.Elem().IsInterface() {
+ t = t.Elem()
+ n.SetOp(ir.ODOTPTR)
+ }
+
+ f := typecheck.Lookdot(n, t, 0)
+ assert(f != nil)
+
+ if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
+ n.SetOp(ir.OCALLPART)
+ n.SetType(typecheck.MethodValueWrapper(n).Type())
+ }
+ return n
+}
+
+// Corresponds to typecheck.typecheckMethodExpr.
+func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
+ t := n.X.Type()
+
+ // Compute the method set for t.
+ var ms *types.Fields
+ if t.IsInterface() {
+ ms = t.Fields()
+ } else {
+ mt := types.ReceiverBaseType(t)
+ typecheck.CalcMethods(mt)
+ ms = mt.AllMethods()
+
+ // The method expression T.m requires a wrapper when T
+ // is different from m's declared receiver type. We
+ // normally generate these wrappers while writing out
+ // runtime type descriptors, which is always done for
+ // types declared at package scope. However, we need
+ // to make sure to generate wrappers for anonymous
+ // receiver types too.
+ if mt.Sym() == nil {
+ typecheck.NeedRuntimeType(t)
+ }
+ }
+
+ s := n.Sel
+ m := typecheck.Lookdot1(n, s, t, ms, 0)
+ assert(m != nil)
+
+ n.SetOp(ir.OMETHEXPR)
+ n.Selection = m
+ n.SetType(typecheck.NewMethodType(m.Type, n.X.Type()))
+ return n
+}
+
+// Corresponds to typecheck.tcAppend.
+func transformAppend(n *ir.CallExpr) ir.Node {
+ transformArgs(n)
+ args := n.Args
+ t := args[0].Type()
+ assert(t.IsSlice())
+
+ if n.IsDDD {
+ if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
+ return n
+ }
+
+ args[1] = assignconvfn(args[1], t.Underlying())
+ return n
+ }
+
+ as := args[1:]
+ for i, n := range as {
+ assert(n.Type() != nil)
+ as[i] = assignconvfn(n, t.Elem())
+ }
+ return n
+}
+
+// Corresponds to typecheck.tcComplex.
+func transformComplex(n *ir.BinaryExpr) ir.Node {
+ l := n.X
+ r := n.Y
+
+ assert(types.Identical(l.Type(), r.Type()))
+
+ var t *types.Type
+ switch l.Type().Kind() {
+ case types.TFLOAT32:
+ t = types.Types[types.TCOMPLEX64]
+ case types.TFLOAT64:
+ t = types.Types[types.TCOMPLEX128]
+ default:
+ panic(fmt.Sprintf("transformComplex: unexpected type %v", l.Type()))
+ }
+
+ // Must set the type here for generics, because this can't be determined
+ // by substitution of the generic types.
+ typed(t, n)
+ return n
+}
+
+// Corresponds to typecheck.tcDelete.
+func transformDelete(n *ir.CallExpr) ir.Node {
+ transformArgs(n)
+ args := n.Args
+ assert(len(args) == 2)
+
+ l := args[0]
+ r := args[1]
+
+ args[1] = assignconvfn(r, l.Type().Key())
+ return n
+}
+
+// Corresponds to typecheck.tcMake.
+func transformMake(n *ir.CallExpr) ir.Node {
+ args := n.Args
+
+ n.Args = nil
+ l := args[0]
+ t := l.Type()
+ assert(t != nil)
+
+ i := 1
+ var nn ir.Node
+ switch t.Kind() {
+ case types.TSLICE:
+ l = args[i]
+ i++
+ var r ir.Node
+ if i < len(args) {
+ r = args[i]
+ i++
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
+
+ case types.TMAP:
+ if i < len(args) {
+ l = args[i]
+ i++
+ } else {
+ l = ir.NewInt(0)
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
+ nn.SetEsc(n.Esc())
+
+ case types.TCHAN:
+ l = nil
+ if i < len(args) {
+ l = args[i]
+ i++
+ } else {
+ l = ir.NewInt(0)
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
+ default:
+ panic(fmt.Sprintf("transformMake: unexpected type %v", t))
+ }
+
+ assert(i == len(args))
+ typed(n.Type(), nn)
+ return nn
+}
+
+// Corresponds to typecheck.tcPanic.
+func transformPanic(n *ir.UnaryExpr) ir.Node {
+ n.X = assignconvfn(n.X, types.Types[types.TINTER])
+ return n
+}
+
+// Corresponds to typecheck.tcPrint.
+func transformPrint(n *ir.CallExpr) ir.Node {
+ transformArgs(n)
+ return n
+}
+
+// Corresponds to typecheck.tcRealImag.
+func transformRealImag(n *ir.UnaryExpr) ir.Node {
+ l := n.X
+ var t *types.Type
+
+ // Determine result type.
+ switch l.Type().Kind() {
+ case types.TCOMPLEX64:
+ t = types.Types[types.TFLOAT32]
+ case types.TCOMPLEX128:
+ t = types.Types[types.TFLOAT64]
+ default:
+ panic(fmt.Sprintf("transformRealImag: unexpected type %v", l.Type()))
+ }
+
+ // Must set the type here for generics, because this can't be determined
+ // by substitution of the generic types.
+ typed(t, n)
+ return n
+}
+
+// Corresponds to typecheck.tcLenCap.
+func transformLenCap(n *ir.UnaryExpr) ir.Node {
+ n.X = implicitstar(n.X)
+ return n
+}
+
+// Corresponds to Builtin part of tcCall.
+func transformBuiltin(n *ir.CallExpr) ir.Node {
+ // n.Type() can be nil for builtins with no return value
+ assert(n.Typecheck() == 1)
+ fun := n.X.(*ir.Name)
+ op := fun.BuiltinOp
+
+ switch op {
+ case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
+ n.SetOp(op)
+ n.X = nil
+ switch op {
+ case ir.OAPPEND:
+ return transformAppend(n)
+ case ir.ODELETE:
+ return transformDelete(n)
+ case ir.OMAKE:
+ return transformMake(n)
+ case ir.OPRINT, ir.OPRINTN:
+ return transformPrint(n)
+ case ir.ORECOVER:
+ // nothing more to do
+ return n
+ }
+
+ case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
+ transformArgs(n)
+ fallthrough
+
+ case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
+ u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
+ switch op {
+ case ir.OCAP, ir.OLEN:
+ return transformLenCap(u1.(*ir.UnaryExpr))
+ case ir.OREAL, ir.OIMAG:
+ return transformRealImag(u1.(*ir.UnaryExpr))
+ case ir.OPANIC:
+ return transformPanic(u1.(*ir.UnaryExpr))
+ case ir.OCLOSE, ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ // nothing more to do
+ return u1
+ }
+
+ case ir.OCOMPLEX, ir.OCOPY:
+ transformArgs(n)
+ b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
+ n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
+ if op == ir.OCOPY {
+ // nothing more to do
+ return n1
+ }
+ return transformComplex(n1.(*ir.BinaryExpr))
+
+ default:
+ panic(fmt.Sprintf("transformBuiltin: unexpected op %v", op))
+ }
+
+ return n
+}
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index 7ab1670a45..24d141e8a2 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -366,9 +366,9 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
}
l := l.(*ir.StructKeyExpr)
- f := lookdot1(nil, l.Field, t, t.Fields(), 0)
+ f := Lookdot1(nil, l.Field, t, t.Fields(), 0)
if f == nil {
- if ci := lookdot1(nil, l.Field, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
+ if ci := Lookdot1(nil, l.Field, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
if visible(ci.Sym) {
base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", l.Field, t, ci.Sym)
} else if nonexported(l.Field) && l.Field.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
@@ -496,7 +496,7 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
return n
}
- if lookdot(n, t, 0) == nil {
+ if Lookdot(n, t, 0) == nil {
// Legitimate field or method lookup failed, try to explain the error
switch {
case t.IsEmptyInterface():
@@ -506,12 +506,12 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
// Pointer to interface is almost always a mistake.
base.Errorf("%v undefined (type %v is pointer to interface, not interface)", n, n.X.Type())
- case lookdot(n, t, 1) != nil:
+ case Lookdot(n, t, 1) != nil:
// Field or method matches by name, but it is not exported.
base.Errorf("%v undefined (cannot refer to unexported field or method %v)", n, n.Sel)
default:
- if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
+ if mt := Lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
base.Errorf("%v undefined (type %v has no field or method %v, but does have %v)", n, n.X.Type(), n.Sel, mt.Sym)
} else {
base.Errorf("%v undefined (type %v has no field or method %v)", n, n.X.Type(), n.Sel)
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index f06a8623d0..54f7cd9efa 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -1058,7 +1058,11 @@ func needTwoArgs(n *ir.CallExpr) (ir.Node, ir.Node, bool) {
return n.Args[0], n.Args[1], true
}
-func lookdot1(errnode ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
+// Lookdot1 looks up the specified method s in the list fs of methods, returning
+// the matching field or nil. If dostrcmp is 0, it matches the symbols. If
+// dostrcmp is 1, it matches by name exactly. If dostrcmp is 2, it matches names
+// with case folding.
+func Lookdot1(errnode ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
var r *types.Field
for _, f := range fs.Slice() {
if dostrcmp != 0 && f.Sym.Name == s.Name {
@@ -1123,9 +1127,9 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
}
s := n.Sel
- m := lookdot1(n, s, t, ms, 0)
+ m := Lookdot1(n, s, t, ms, 0)
if m == nil {
- if lookdot1(n, s, t, ms, 1) != nil {
+ if Lookdot1(n, s, t, ms, 1) != nil {
base.Errorf("%v undefined (cannot refer to unexported method %v)", n, s)
} else if _, ambig := dotpath(s, t, nil, false); ambig {
base.Errorf("%v undefined (ambiguous selector)", n) // method or field
@@ -1155,20 +1159,26 @@ func derefall(t *types.Type) *types.Type {
return t
}
-func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
+// Lookdot looks up field or method n.Sel in the type t and returns the matching
+// field. It transforms the op of node n to ODOTINTER or ODOTMETH, if appropriate.
+// It also may add a StarExpr node to n.X as needed for access to non-pointer
+// methods. If dostrcmp is 0, it matches the field/method with the exact symbol
+// as n.Sel (appropriate for exported fields). If dostrcmp is 1, it matches by name
+// exactly. If dostrcmp is 2, it matches names with case folding.
+func Lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
s := n.Sel
types.CalcSize(t)
var f1 *types.Field
if t.IsStruct() || t.IsInterface() {
- f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
+ f1 = Lookdot1(n, s, t, t.Fields(), dostrcmp)
}
var f2 *types.Field
if n.X.Type() == t || n.X.Type().Sym() == nil {
mt := types.ReceiverBaseType(t)
if mt != nil {
- f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
+ f2 = Lookdot1(n, s, mt, mt.Methods(), dostrcmp)
}
}
@@ -1181,7 +1191,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
base.Errorf("%v is both field and method", n.Sel)
}
if f1.Offset == types.BADWIDTH {
- base.Fatalf("lookdot badwidth t=%v, f1=%v@%p", t, f1, f1)
+ base.Fatalf("Lookdot badwidth t=%v, f1=%v@%p", t, f1, f1)
}
n.Selection = f1
n.SetType(f1.Type)