aboutsummaryrefslogtreecommitdiff
path: root/resolve/resolve.go
diff options
context:
space:
mode:
Diffstat (limited to 'resolve/resolve.go')
-rw-r--r--resolve/resolve.go40
1 files changed, 30 insertions, 10 deletions
diff --git a/resolve/resolve.go b/resolve/resolve.go
index 0bc9ac0..51325bd 100644
--- a/resolve/resolve.go
+++ b/resolve/resolve.go
@@ -765,7 +765,9 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
r.push(b)
var seenOptional bool
- var star, starStar *syntax.Ident // *args, **kwargs
+ 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:
@@ -786,7 +788,7 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
if starStar != nil {
r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
} else if star != nil {
- r.errorf(param.OpPos, "optional parameter may not follow *%s", star.Name)
+ numKwonlyParams++
}
if id := param.X.(*syntax.Ident); r.bind(id) {
r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
@@ -794,30 +796,48 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
seenOptional = true
case *syntax.UnaryExpr:
- // *args or **kwargs
- id := param.X.(*syntax.Ident)
+ // * or *args or **kwargs
if param.Op == syntax.STAR {
if starStar != nil {
- r.errorf(param.OpPos, "*%s parameter may not follow **%s", id.Name, starStar.Name)
+ 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 = id
+ star = param
}
} else {
if starStar != nil {
r.errorf(param.OpPos, "multiple ** parameters not allowed")
- } else {
- starStar = id
}
+ 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 optional parameters")
}
}
- function.HasVarargs = star != nil
- function.HasKwargs = starStar != nil
+ 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,