mirror of
https://github.com/golang/go
synced 2024-11-26 17:46:57 -07:00
go/types: split out function instantiation from index expr
This is a port of CL 308371 to go/types. The only meaningful change from that CL is to use explicit return values in Checker.indexExpr, which I felt was more readable. I made the same change in types2 to keep them in sync Change-Id: I3380c03fe49d3bf4167cadad305abe942785af19 Reviewed-on: https://go-review.googlesource.com/c/go/+/314432 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
5b328c4a2f
commit
f893f35d9f
@ -20,7 +20,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
|||||||
switch x.mode {
|
switch x.mode {
|
||||||
case invalid:
|
case invalid:
|
||||||
check.use(e.Index)
|
check.use(e.Index)
|
||||||
return
|
return false
|
||||||
|
|
||||||
case typexpr:
|
case typexpr:
|
||||||
// type instantiation
|
// type instantiation
|
||||||
@ -29,7 +29,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
|||||||
if x.typ != Typ[Invalid] {
|
if x.typ != Typ[Invalid] {
|
||||||
x.mode = typexpr
|
x.mode = typexpr
|
||||||
}
|
}
|
||||||
return
|
return false
|
||||||
|
|
||||||
case value:
|
case value:
|
||||||
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
||||||
@ -196,7 +196,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
check.index(index, length)
|
check.index(index, length)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"unicode"
|
"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.
|
// The operand x must be the evaluation of inst.X and its type must be a signature.
|
||||||
func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) {
|
func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) {
|
||||||
xlist := typeparams.UnpackExpr(inst.Index)
|
xlist := typeparams.UnpackExpr(inst.Index)
|
||||||
@ -71,8 +71,16 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) {
|
|||||||
x.expr = inst
|
x.expr = inst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind {
|
func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
|
||||||
check.exprOrType(x, call.Fun)
|
if iexpr, _ := call.Fun.(*ast.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 {
|
switch x.mode {
|
||||||
case invalid:
|
case invalid:
|
||||||
@ -121,49 +129,48 @@ func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind {
|
|||||||
check.hasCallOrRecv = true
|
check.hasCallOrRecv = true
|
||||||
}
|
}
|
||||||
return predeclaredFuncs[id].kind
|
return predeclaredFuncs[id].kind
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
// ordinary function/method call
|
||||||
// function/method call
|
cgocall := x.mode == cgofunc
|
||||||
cgocall := x.mode == cgofunc
|
|
||||||
|
|
||||||
sig := asSignature(x.typ)
|
sig := asSignature(x.typ)
|
||||||
if sig == nil {
|
if sig == nil {
|
||||||
check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
|
check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
x.expr = call
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate arguments
|
|
||||||
args, _ := check.exprList(call.Args, 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
|
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
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// evaluate arguments
|
||||||
|
args, _ := check.exprList(call.Args, 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 []ast.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
|
func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
|
||||||
|
@ -308,6 +308,33 @@ func (check *Checker) processDelayed(top int) {
|
|||||||
check.delayed = check.delayed[:top]
|
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() {
|
func (check *Checker) recordUntyped() {
|
||||||
if !debug && check.Types == nil {
|
if !debug && check.Types == nil {
|
||||||
return // nothing to do
|
return // nothing to do
|
||||||
|
@ -1027,31 +1027,7 @@ func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kind := check.exprInternal(x, e, hint)
|
kind := check.exprInternal(x, e, hint)
|
||||||
|
check.record(x)
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
return kind
|
return kind
|
||||||
}
|
}
|
||||||
@ -1340,7 +1316,9 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||||||
check.selector(x, e)
|
check.selector(x, e)
|
||||||
|
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
check.indexExpr(x, e)
|
if check.indexExpr(x, e) {
|
||||||
|
check.funcInst(x, e)
|
||||||
|
}
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
@ -1378,7 +1356,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||||||
x.typ = T
|
x.typ = T
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
return check.call(x, e)
|
return check.callExpr(x, e)
|
||||||
|
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
check.exprOrType(x, e.X)
|
check.exprOrType(x, e.X)
|
||||||
|
@ -12,27 +12,30 @@ import (
|
|||||||
"go/internal/typeparams"
|
"go/internal/typeparams"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (check *Checker) indexExpr(x *operand, e *ast.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 *ast.IndexExpr) (isFuncInst bool) {
|
||||||
check.exprOrType(x, e.X)
|
check.exprOrType(x, e.X)
|
||||||
if x.mode == invalid {
|
|
||||||
check.use(typeparams.UnpackExpr(e.Index)...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.mode == typexpr {
|
switch x.mode {
|
||||||
|
case invalid:
|
||||||
|
check.use(typeparams.UnpackExpr(e.Index)...)
|
||||||
|
return false
|
||||||
|
|
||||||
|
case typexpr:
|
||||||
// type instantiation
|
// type instantiation
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
x.typ = check.varType(e)
|
x.typ = check.varType(e)
|
||||||
if x.typ != Typ[Invalid] {
|
if x.typ != Typ[Invalid] {
|
||||||
x.mode = typexpr
|
x.mode = typexpr
|
||||||
}
|
}
|
||||||
return
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
if x.mode == value {
|
case value:
|
||||||
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
||||||
check.funcInst(x, e)
|
// function instantiation
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +184,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check.index(e.Index, length)
|
check.index(e.Index, length)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
|
func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
|
||||||
|
Loading…
Reference in New Issue
Block a user