]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: split out function instantiation from index expr
authorRob Findley <rfindley@google.com>
Tue, 27 Apr 2021 20:54:58 +0000 (16:54 -0400)
committerRobert Findley <rfindley@google.com>
Wed, 28 Apr 2021 17:11:15 +0000 (17:11 +0000)
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>
src/cmd/compile/internal/types2/index.go
src/go/types/call.go
src/go/types/check.go
src/go/types/expr.go
src/go/types/index.go

index b30799d37c15479025c0f1edacf28214f862af06..d9a402f212ff1c118bc28586b6a3a7185e3e071f 100644 (file)
@@ -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) {
index 4834bd02c12a94c2e2722e5d089e681884acdd62..e23bdb830d6b89d1c909ec18086d751f7aab43ec 100644 (file)
@@ -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
-               }
+       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)
+       // 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:
+       // 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
-               }
-               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
                }
+               x.typ = sig.results.vars[0].typ // unpack tuple
+       default:
+               x.mode = value
+               x.typ = sig.results
+       }
+       x.expr = call
+       check.hasCallOrRecv = true
 
-               return statement
+       // 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) {
index 4053fe2f4aad53f0bfcb1815b406ad2294e1b63f..83568c9353d70355283be35805e4c745c8bda185 100644 (file)
@@ -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
index bdab7d9aa65c1e1fc1cdec9f8c8235294b9f20ab..4055cdd080c01add3b5985c5ed26e7a90389ceb0 100644 (file)
@@ -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)
index f497b06dad9bb59d9c129372f75d41235cd35d6c..f51c3f6acf96c50ea3394bded4ee28335e45ed08 100644 (file)
@@ -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 {
+
+       switch x.mode {
+       case invalid:
                check.use(typeparams.UnpackExpr(e.Index)...)
-               return
-       }
+               return false
 
-       if x.mode == typexpr {
+       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) {