mirror of
https://github.com/golang/go
synced 2024-11-11 22:20:22 -07:00
cmd/compile/internal/types2: split out function instantiation from index expr
Also, factor out recording of type/value information after evaluating an expression into an operand, so that we can use it when handling instantiation expressions manually. Change-Id: I6776e6cc243558079d6a203f2fe0a6ae0ecc33de Reviewed-on: https://go-review.googlesource.com/c/go/+/308371 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
36c5f902f9
commit
a6d95b4508
@ -12,7 +12,7 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// funcInst type-checks a function instantiaton inst and returns the result in x.
|
||||
// funcInst type-checks a function instantiation inst and returns the result in x.
|
||||
// The operand x must be the evaluation of inst.X and its type must be a signature.
|
||||
func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
|
||||
xlist := unpackExpr(inst.Index)
|
||||
@ -66,8 +66,16 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
|
||||
x.expr = inst
|
||||
}
|
||||
|
||||
func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
|
||||
check.exprOrType(x, call.Fun)
|
||||
func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
|
||||
if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
|
||||
if check.indexExpr(x, iexpr) {
|
||||
check.funcInst(x, iexpr)
|
||||
}
|
||||
x.expr = iexpr
|
||||
check.record(x)
|
||||
} else {
|
||||
check.exprOrType(x, call.Fun)
|
||||
}
|
||||
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
@ -116,49 +124,48 @@ func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
|
||||
check.hasCallOrRecv = true
|
||||
}
|
||||
return predeclaredFuncs[id].kind
|
||||
}
|
||||
|
||||
default:
|
||||
// function/method call
|
||||
cgocall := x.mode == cgofunc
|
||||
// ordinary function/method call
|
||||
cgocall := x.mode == cgofunc
|
||||
|
||||
sig := asSignature(x.typ)
|
||||
if sig == nil {
|
||||
check.errorf(x, invalidOp+"cannot call non-function %s", x)
|
||||
x.mode = invalid
|
||||
x.expr = call
|
||||
return statement
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args, _ := check.exprList(call.ArgList, false)
|
||||
sig = check.arguments(call, sig, args)
|
||||
|
||||
// determine result
|
||||
switch sig.results.Len() {
|
||||
case 0:
|
||||
x.mode = novalue
|
||||
case 1:
|
||||
if cgocall {
|
||||
x.mode = commaerr
|
||||
} else {
|
||||
x.mode = value
|
||||
}
|
||||
x.typ = sig.results.vars[0].typ // unpack tuple
|
||||
default:
|
||||
x.mode = value
|
||||
x.typ = sig.results
|
||||
}
|
||||
sig := asSignature(x.typ)
|
||||
if sig == nil {
|
||||
check.errorf(x, invalidOp+"cannot call non-function %s", x)
|
||||
x.mode = invalid
|
||||
x.expr = call
|
||||
check.hasCallOrRecv = true
|
||||
|
||||
// if type inference failed, a parametrized result must be invalidated
|
||||
// (operands cannot have a parametrized type)
|
||||
if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) {
|
||||
x.mode = invalid
|
||||
}
|
||||
|
||||
return statement
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args, _ := check.exprList(call.ArgList, false)
|
||||
sig = check.arguments(call, sig, args)
|
||||
|
||||
// determine result
|
||||
switch sig.results.Len() {
|
||||
case 0:
|
||||
x.mode = novalue
|
||||
case 1:
|
||||
if cgocall {
|
||||
x.mode = commaerr
|
||||
} else {
|
||||
x.mode = value
|
||||
}
|
||||
x.typ = sig.results.vars[0].typ // unpack tuple
|
||||
default:
|
||||
x.mode = value
|
||||
x.typ = sig.results
|
||||
}
|
||||
x.expr = call
|
||||
check.hasCallOrRecv = true
|
||||
|
||||
// if type inference failed, a parametrized result must be invalidated
|
||||
// (operands cannot have a parametrized type)
|
||||
if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) {
|
||||
x.mode = invalid
|
||||
}
|
||||
|
||||
return statement
|
||||
}
|
||||
|
||||
func (check *Checker) exprList(elist []syntax.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
|
||||
|
@ -307,6 +307,33 @@ func (check *Checker) processDelayed(top int) {
|
||||
check.delayed = check.delayed[:top]
|
||||
}
|
||||
|
||||
func (check *Checker) record(x *operand) {
|
||||
// convert x into a user-friendly set of values
|
||||
// TODO(gri) this code can be simplified
|
||||
var typ Type
|
||||
var val constant.Value
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
typ = Typ[Invalid]
|
||||
case novalue:
|
||||
typ = (*Tuple)(nil)
|
||||
case constant_:
|
||||
typ = x.typ
|
||||
val = x.val
|
||||
default:
|
||||
typ = x.typ
|
||||
}
|
||||
assert(x.expr != nil && typ != nil)
|
||||
|
||||
if isUntyped(typ) {
|
||||
// delay type and value recording until we know the type
|
||||
// or until the end of type checking
|
||||
check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
|
||||
} else {
|
||||
check.recordTypeAndValue(x.expr, x.mode, typ, val)
|
||||
}
|
||||
}
|
||||
|
||||
func (check *Checker) recordUntyped() {
|
||||
if !debug && check.Types == nil {
|
||||
return // nothing to do
|
||||
|
@ -1068,31 +1068,7 @@ func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
|
||||
}
|
||||
|
||||
kind := check.exprInternal(x, e, hint)
|
||||
|
||||
// convert x into a user-friendly set of values
|
||||
// TODO(gri) this code can be simplified
|
||||
var typ Type
|
||||
var val constant.Value
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
typ = Typ[Invalid]
|
||||
case novalue:
|
||||
typ = (*Tuple)(nil)
|
||||
case constant_:
|
||||
typ = x.typ
|
||||
val = x.val
|
||||
default:
|
||||
typ = x.typ
|
||||
}
|
||||
assert(x.expr != nil && typ != nil)
|
||||
|
||||
if isUntyped(typ) {
|
||||
// delay type and value recording until we know the type
|
||||
// or until the end of type checking
|
||||
check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
|
||||
} else {
|
||||
check.recordTypeAndValue(e, x.mode, typ, val)
|
||||
}
|
||||
check.record(x)
|
||||
|
||||
return kind
|
||||
}
|
||||
@ -1387,7 +1363,9 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
check.selector(x, e)
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
check.indexExpr(x, e)
|
||||
if check.indexExpr(x, e) {
|
||||
check.funcInst(x, e)
|
||||
}
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
@ -1428,7 +1406,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
goto Error
|
||||
|
||||
case *syntax.CallExpr:
|
||||
return check.call(x, e)
|
||||
return check.callExpr(x, e)
|
||||
|
||||
// case *syntax.UnaryExpr:
|
||||
// check.expr(x, e.X)
|
||||
|
@ -11,14 +11,18 @@ import (
|
||||
"go/constant"
|
||||
)
|
||||
|
||||
func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) {
|
||||
// If e is a valid function instantiation, indexExpr returns true.
|
||||
// In that case x represents the uninstantiated function value and
|
||||
// it is the caller's responsibility to instantiate the function.
|
||||
func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst bool) {
|
||||
check.exprOrType(x, e.X)
|
||||
if x.mode == invalid {
|
||||
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
check.use(e.Index)
|
||||
return
|
||||
}
|
||||
|
||||
if x.mode == typexpr {
|
||||
case typexpr:
|
||||
// type instantiation
|
||||
x.mode = invalid
|
||||
x.typ = check.varType(e)
|
||||
@ -26,13 +30,11 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) {
|
||||
x.mode = typexpr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if x.mode == value {
|
||||
case value:
|
||||
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
||||
// function instantiation
|
||||
check.funcInst(x, e)
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,6 +196,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) {
|
||||
}
|
||||
|
||||
check.index(index, length)
|
||||
return
|
||||
}
|
||||
|
||||
func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
||||
|
Loading…
Reference in New Issue
Block a user