n.Addable = n.Left.Addable
}
- case OITAB:
+ case OITAB, OIDATA:
n.Addable = n.Left.Addable
}
Thearch.Gmove(&n1, res)
Regfree(&n1)
- // interface table is first word of interface value
case OITAB:
+ // interface table is first word of interface value
var n1 Node
Igen(nl, &n1, res)
+ n1.Type = n.Type
+ Thearch.Gmove(&n1, res)
+ Regfree(&n1)
+ case OIDATA:
+ // interface data is second word of interface value
+ var n1 Node
+ Igen(nl, &n1, res)
n1.Type = n.Type
+ n1.Xoffset += int64(Widthptr)
Thearch.Gmove(&n1, res)
Regfree(&n1)
func Ismem(n *Node) bool {
switch n.Op {
case OITAB,
+ OIDATA,
OSPTR,
OLEN,
OCAP,
}
a.Type = obj.TYPE_ADDR
- // itable of interface value
case OITAB:
+ // itable of interface value
Naddr(a, n.Left)
-
if a.Type == obj.TYPE_CONST && a.Offset == 0 {
break // itab(nil)
}
a.Etype = uint8(Tptr)
a.Width = int64(Widthptr)
+ case OIDATA:
+ // idata of interface value
+ Naddr(a, n.Left)
+ if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+ break // idata(nil)
+ }
+ if isdirectiface(n.Type) {
+ a.Etype = uint8(Simtype[n.Type.Etype])
+ } else {
+ a.Etype = uint8(Tptr)
+ }
+ a.Offset += int64(Widthptr)
+ a.Width = int64(Widthptr)
+
// pointer in a string or slice
case OSPTR:
Naddr(a, n.Left)
OINLCALL: "INLCALL",
OEFACE: "EFACE",
OITAB: "ITAB",
+ OIDATA: "IDATA",
OSPTR: "SPTR",
OCLOSUREVAR: "CLOSUREVAR",
OCFUNC: "CFUNC",
goto ret
- case OITAB:
+ case OITAB, OIDATA:
instrumentnode(&n.Left, init, 0, 0)
goto ret
a := s.expr(n.Left)
return s.newValue1(ssa.OpITab, n.Type, a)
+ case OIDATA:
+ a := s.expr(n.Left)
+ return s.newValue1(ssa.OpIData, n.Type, a)
+
case OEFACE:
tab := s.expr(n.Left)
data := s.expr(n.Right)
return typ
}
+// ifaceData loads the data field from an interface.
+// The concrete type must be known to have type t.
+// It follows the pointer if !isdirectiface(t).
+func ifaceData(n *Node, t *Type) *Node {
+ ptr := NodSym(OIDATA, n, nil)
+ if isdirectiface(t) {
+ ptr.Type = t
+ ptr.Typecheck = 1
+ return ptr
+ }
+ ptr.Type = Ptrto(t)
+ ptr.Bounded = true
+ ptr.Typecheck = 1
+ ind := Nod(OIND, ptr, nil)
+ ind.Type = t
+ ind.Typecheck = 1
+ return ind
+}
+
// iet returns 'T' if t is a concrete type,
// 'I' if t is an interface type, and 'E' if t is an empty interface type.
// It is used to build calls to the conv* and assert* runtime routines.
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal, or slice index pair)
- _ // was OPARAM, but cannot remove without breaking binary blob in builtin.go
+ OIDATA // data word of an interface value in Left; TODO: move next to OITAB once it is easier to regenerate the binary blob in builtin.go (issues 15835, 15839)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
n.Type = Ptrto(Types[TUINTPTR])
break OpSwitch
+ case OIDATA:
+ // Whoever creates the OIDATA node must know a priori the concrete type at that moment,
+ // usually by just having checked the OITAB.
+ Fatalf("cannot typecheck interface data %v", n)
+ break OpSwitch
+
case OSPTR:
ok |= Erv
n.Left = typecheck(n.Left, Erv)
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
- case OSPTR, OITAB:
+ case OSPTR, OITAB, OIDATA:
n.Left = walkexpr(n.Left, init)
case OLEN, OCAP:
toKind := t.iet()
res := n.List.First()
+ scalar := !haspointers(res.Type)
// Avoid runtime calls in a few cases of the form _, ok := i.(T).
// This is faster and shorter and allows the corresponding assertX2X2
// routines to skip nil checks on their last argument.
- if isblank(res) {
+ // Also avoid runtime calls for converting interfaces to scalar concrete types.
+ if isblank(res) || (scalar && toKind == 'T') {
var fast *Node
switch toKind {
case 'T':
fast = Nod(ONE, nodnil(), tab)
}
if fast != nil {
- if Debug_typeassert > 0 {
- Warn("type assertion (ok only) inlined")
+ if isblank(res) {
+ if Debug_typeassert > 0 {
+ Warn("type assertion (ok only) inlined")
+ }
+ n = Nod(OAS, ok, fast)
+ n = typecheck(n, Etop)
+ } else {
+ if Debug_typeassert > 0 {
+ Warn("type assertion (scalar result) inlined")
+ }
+ n = Nod(OIF, ok, nil)
+ n.Likely = 1
+ if isblank(ok) {
+ n.Left = fast
+ } else {
+ n.Ninit.Set1(Nod(OAS, ok, fast))
+ }
+ n.Nbody.Set1(Nod(OAS, res, ifaceData(from, res.Type)))
+ n.Rlist.Set1(Nod(OAS, res, nil))
+ n = typecheck(n, Etop)
}
- n = Nod(OAS, ok, fast)
- n = typecheck(n, Etop)
break
}
}
}
func assertbig2(x interface{}) (complex128, bool) {
- z, ok := x.(complex128) // ERROR "type assertion not inlined"
+ z, ok := x.(complex128) // ERROR "type assertion .scalar result. inlined"
return z, ok
}
_, ok := x.(complex128) // ERROR "type assertion [(]ok only[)] inlined"
return 0, ok
}
+
+func assertslice(x interface{}) []int {
+ return x.([]int) // ERROR "type assertion not inlined"
+}
+
+func assertslice2(x interface{}) ([]int, bool) {
+ z, ok := x.([]int) // ERROR "type assertion not inlined"
+ return z, ok
+}
+
+func assertslice2ok(x interface{}) ([]int, bool) {
+ _, ok := x.([]int) // ERROR "type assertion [(]ok only[)] inlined"
+ return nil, ok
+}