"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)
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:
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) {
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
}
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
}
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
}
x.typ = T
case *ast.CallExpr:
- return check.call(x, e)
+ return check.callExpr(x, e)
case *ast.StarExpr:
check.exprOrType(x, e.X)
"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
}
}
}
check.index(e.Index, length)
+ return false
}
func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {