1
0
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:
Rob Findley 2021-04-27 16:54:58 -04:00 committed by Robert Findley
parent 5b328c4a2f
commit f893f35d9f
5 changed files with 98 additions and 82 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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) {