in resolve/resolve.go [799:896]
func (r *resolver) function(function *Function, pos syntax.Position) {
// Resolve defaults in enclosing environment.
for _, param := range function.Params {
if binary, ok := param.(*syntax.BinaryExpr); ok {
r.expr(binary.Y)
}
}
// Enter function block.
b := &block{function: function}
r.push(b)
var seenOptional bool
var star *syntax.UnaryExpr // * or *args param
var starStar *syntax.Ident // **kwargs ident
var numKwonlyParams int
for _, param := range function.Params {
switch param := param.(type) {
case *syntax.Ident:
// e.g. x
if starStar != nil {
r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name)
} else if star != nil {
numKwonlyParams++
} else if seenOptional {
r.errorf(param.NamePos, "required parameter may not follow optional")
}
if r.bind(param) {
r.errorf(param.NamePos, "duplicate parameter: %s", param.Name)
}
case *syntax.BinaryExpr:
// e.g. y=dflt
if starStar != nil {
r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
} else if star != nil {
numKwonlyParams++
}
if id := param.X.(*syntax.Ident); r.bind(id) {
r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
}
seenOptional = true
case *syntax.UnaryExpr:
// * or *args or **kwargs
if param.Op == syntax.STAR {
if starStar != nil {
r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name)
} else if star != nil {
r.errorf(param.OpPos, "multiple * parameters not allowed")
} else {
star = param
}
} else {
if starStar != nil {
r.errorf(param.OpPos, "multiple ** parameters not allowed")
}
starStar = param.X.(*syntax.Ident)
}
}
}
// Bind the *args and **kwargs parameters at the end,
// so that regular parameters a/b/c are contiguous and
// there is no hole for the "*":
// def f(a, b, *args, c=0, **kwargs)
// def f(a, b, *, c=0, **kwargs)
if star != nil {
if id, _ := star.X.(*syntax.Ident); id != nil {
// *args
if r.bind(id) {
r.errorf(id.NamePos, "duplicate parameter: %s", id.Name)
}
function.HasVarargs = true
} else if numKwonlyParams == 0 {
r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters")
}
}
if starStar != nil {
if r.bind(starStar) {
r.errorf(starStar.NamePos, "duplicate parameter: %s", starStar.Name)
}
function.HasKwargs = true
}
function.NumKwonlyParams = numKwonlyParams
r.stmts(function.Body)
// Resolve all uses of this function's local vars,
// and keep just the remaining uses of free/global vars.
b.resolveLocalUses()
// Leave function block.
r.pop()
// References within the function body to globals are not
// resolved until the end of the module.
}