From f893f35d9f7acc3bad32efeac693a44849b5e895 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 27 Apr 2021 16:54:58 -0400 Subject: [PATCH] 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 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/index.go | 6 +- src/go/types/call.go | 89 +++++++++++++----------- src/go/types/check.go | 27 +++++++ src/go/types/expr.go | 32 ++------- src/go/types/index.go | 26 ++++--- 5 files changed, 98 insertions(+), 82 deletions(-) diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index b30799d37c1..d9a402f212f 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -20,7 +20,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo switch x.mode { case invalid: check.use(e.Index) - return + return false case typexpr: // type instantiation @@ -29,7 +29,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo if x.typ != Typ[Invalid] { x.mode = typexpr } - return + return false case value: 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) - return + return false } func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { diff --git a/src/go/types/call.go b/src/go/types/call.go index 4834bd02c12..e23bdb830d6 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -14,7 +14,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 *ast.IndexExpr) { xlist := typeparams.UnpackExpr(inst.Index) @@ -71,8 +71,16 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { x.expr = inst } -func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind { - check.exprOrType(x, call.Fun) +func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { + 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 { case invalid: @@ -121,49 +129,48 @@ func (check *Checker) call(x *operand, call *ast.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.invalidOp(x, _InvalidCall, "cannot call non-function %s", x) - 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 - } + sig := asSignature(x.typ) + if sig == nil { + check.invalidOp(x, _InvalidCall, "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.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) { diff --git a/src/go/types/check.go b/src/go/types/check.go index 4053fe2f4aa..83568c9353d 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -308,6 +308,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 diff --git a/src/go/types/expr.go b/src/go/types/expr.go index bdab7d9aa65..4055cdd080c 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1027,31 +1027,7 @@ func (check *Checker) rawExpr(x *operand, e ast.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 } @@ -1340,7 +1316,9 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { check.selector(x, e) case *ast.IndexExpr: - check.indexExpr(x, e) + if check.indexExpr(x, e) { + check.funcInst(x, e) + } if x.mode == invalid { goto Error } @@ -1378,7 +1356,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { x.typ = T case *ast.CallExpr: - return check.call(x, e) + return check.callExpr(x, e) case *ast.StarExpr: check.exprOrType(x, e.X) diff --git a/src/go/types/index.go b/src/go/types/index.go index f497b06dad9..f51c3f6acf9 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -12,27 +12,30 @@ import ( "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) - 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 x.mode = invalid x.typ = check.varType(e) if x.typ != Typ[Invalid] { x.mode = typexpr } - return - } + return false - if x.mode == value { + case value: if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { - check.funcInst(x, e) - return + // function instantiation + return true } } @@ -181,6 +184,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) { } check.index(e.Index, length) + return false } func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {