aboutsummaryrefslogtreecommitdiff
path: root/resolve
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2017-11-28 14:19:10 -0500
committerAlan Donovan <adonovan@google.com>2017-11-28 14:19:10 -0500
commit1b9d0e7119bc2aca0cd6be14ea0b8b184dc12bd2 (patch)
treec06c0f00ee1a62deb747e9a8829fea0f04552f0d /resolve
parent48d7cc591137a2a512fedcae4f23beedd678abb7 (diff)
downloadstarlark-go-1b9d0e7119bc2aca0cd6be14ea0b8b184dc12bd2.tar.gz
resolve: add missing check for order of parameters and arguments
Parameters: required before optional Arguments: positional before named
Diffstat (limited to 'resolve')
-rw-r--r--resolve/resolve.go12
-rw-r--r--resolve/testdata/resolve.sky7
2 files changed, 15 insertions, 4 deletions
diff --git a/resolve/resolve.go b/resolve/resolve.go
index 4649914..14fdcdd 100644
--- a/resolve/resolve.go
+++ b/resolve/resolve.go
@@ -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 {
@@ -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)
}
@@ -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:
@@ -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)
@@ -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
diff --git a/resolve/testdata/resolve.sky b/resolve/testdata/resolve.sky
index f8c4c9a..6feaf67 100644
--- a/resolve/testdata/resolve.sky
+++ b/resolve/testdata/resolve.sky
@@ -166,6 +166,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
def f(**kwargs, x): ### `parameter may not follow \*\*kwargs`