Skip to content

Commit

Permalink
resolve: add missing check for order of parameters and arguments
Browse files Browse the repository at this point in the history
Parameters: required before optional
Arguments: positional before named
  • Loading branch information
adonovan committed Nov 28, 2017
1 parent 48d7cc5 commit 1b9d0e7
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
12 changes: 8 additions & 4 deletions resolve/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,7 @@ func (r *resolver) expr(e syntax.Expr) {

case *syntax.CallExpr:
r.expr(e.Fn)
seenVarargs := false
seenKwargs := false
var seenVarargs, seenKwargs, seenNamed bool
for _, arg := range e.Args {
pos, _ := arg.Span()
if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
Expand All @@ -611,12 +610,15 @@ func (r *resolver) expr(e syntax.Expr) {
}
// ignore binop.X
r.expr(binop.Y)
seenNamed = true
} else {
// positional argument
if seenVarargs {
r.errorf(pos, "argument may not follow *args")
} else if seenKwargs {
r.errorf(pos, "argument may not follow **kwargs")
} else if seenNamed {
r.errorf(pos, "positional argument may not follow named")
}
r.expr(arg)
}
Expand Down Expand Up @@ -646,8 +648,7 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
r.push(b)

const allowRebind = false
seenVarargs := false
seenKwargs := false
var seenVarargs, seenKwargs, seenOptional bool
for _, param := range function.Params {
switch param := param.(type) {
case *syntax.Ident:
Expand All @@ -656,6 +657,8 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
r.errorf(pos, "parameter may not follow **kwargs")
} else if seenVarargs {
r.errorf(pos, "parameter may not follow *args")
} else if seenOptional {
r.errorf(pos, "required parameter may not follow optional")
}
if r.bind(param, allowRebind) {
r.errorf(pos, "duplicate parameter: %s", param.Name)
Expand All @@ -671,6 +674,7 @@ func (r *resolver) function(pos syntax.Position, name string, function *syntax.F
if id := param.X.(*syntax.Ident); r.bind(id, allowRebind) {
r.errorf(pos, "duplicate parameter: %s", id.Name)
}
seenOptional = true

case *syntax.UnaryExpr:
// *args or **kwargs
Expand Down
7 changes: 7 additions & 0 deletions resolve/testdata/resolve.sky
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ continue ### "continue not in a loop"

pass

---
# Positional arguments (and required parameters)
# must appear before named arguments (and optional parameters).

G(x=1, 2) ### `positional argument may not follow named`

def f(x=1, y): pass ### `required parameter may not follow optional`
---
# No parameters may follow **kwargs

Expand Down

0 comments on commit 1b9d0e7

Please sign in to comment.