From a6d95b4508cb65070fd8471ae8018b897da7fc83 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 7 Apr 2021 18:27:08 -0700 Subject: [PATCH] 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 Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 89 +++++++++++++----------- src/cmd/compile/internal/types2/check.go | 27 +++++++ src/cmd/compile/internal/types2/expr.go | 32 ++------- src/cmd/compile/internal/types2/index.go | 19 ++--- 4 files changed, 91 insertions(+), 76 deletions(-) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 5ad8ea9f877..b340c52e746 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -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) { diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 2edcefd4c87..7703d98fa66 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -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 diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 4a2e658a632..76c6e7a3b30 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -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) diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 0f4adab2374..b9b5b532261 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -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) {