Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Named parameters in function and procedure calls

  • Loading branch information...
commit b0743236d4a6887f690c6aac3657b4de2ef911b5 1 parent 19558b4
@nickg authored
View
2  src/dump.c
@@ -51,8 +51,6 @@ static void dump_params(tree_t t)
switch (p.kind) {
case P_POS:
break;
- case P_RANGE:
- assert(false);
case P_NAMED:
printf("%s => ", istr(p.name));
break;
View
131 src/sem.c
@@ -2304,36 +2304,66 @@ static bool sem_maybe_ambiguous(tree_t t)
}
}
+static type_t sem_find_param_type(param_t param, tree_t decl)
+{
+ type_t decl_type = tree_type(decl);
+
+ switch (param.kind) {
+ case P_POS:
+ // Simple case of positional parameters is just the same index
+ // into the port list
+ return type_param(decl_type, param.pos);
+
+ case P_NAMED:
+ // Need to search through the port list for a matching name
+ {
+ const int nports = tree_ports(decl);
+ for (int i = 0; i < nports; i++) {
+ if (tree_ident(tree_port(decl, i)) == param.name)
+ return type_param(decl_type, i);
+ }
+
+ return NULL;
+ }
+
+ default:
+ assert(false);
+ }
+}
+
static bool sem_resolve_overload(tree_t t, tree_t *pick, int *matches,
tree_t *overloads, int n_overloads)
{
*pick = NULL;
*matches = 0;
- const unsigned nparams = tree_params(t);
+ const int nparams = tree_params(t);
// Work out which parameters have ambiguous interpretations
bool ambiguous[nparams];
- for (unsigned i = 0; i < nparams; i++) {
+ for (int i = 0; i < nparams; i++) {
param_t p = tree_param(t, i);
- assert(p.kind == P_POS);
ambiguous[i] = sem_maybe_ambiguous(p.value);
}
// First pass: only check those parameters which are unambiguous
- for (unsigned i = 0; i < nparams; i++) {
+ for (int i = 0; i < nparams; i++) {
if (ambiguous[i])
continue;
type_set_push();
+ param_t p = tree_param(t, i);
+ type_t param_types[n_overloads];
+
for (int j = 0; j < n_overloads; j++) {
- if (overloads[j] != NULL)
- type_set_add(type_param(tree_type(overloads[j]), i));
+ if (overloads[j] != NULL) {
+ param_types[j] = sem_find_param_type(p, overloads[j]);
+ if (param_types[j] != NULL)
+ type_set_add(param_types[j]);
+ }
}
- param_t p = tree_param(t, i);
- assert(p.kind == P_POS);
bool ok = sem_check(p.value);
type_set_pop();
@@ -2343,8 +2373,8 @@ static bool sem_resolve_overload(tree_t t, tree_t *pick, int *matches,
type_t ptype = tree_type(p.value);
for (int j = 0; j < n_overloads; j++) {
if (overloads[j] != NULL) {
- if (!type_eq(type_param(tree_type(overloads[j]), i),
- ptype))
+ if ((param_types[j] == NULL)
+ || !type_eq(param_types[j], ptype))
overloads[j] = NULL;
}
}
@@ -2355,19 +2385,23 @@ static bool sem_resolve_overload(tree_t t, tree_t *pick, int *matches,
// Second pass: now the set of overloads has been constrained check
// those parameters which might be ambiguous
- for (unsigned i = 0; i < nparams; i++) {
+ for (int i = 0; i < nparams; i++) {
if (!ambiguous[i])
continue;
type_set_push();
+ param_t p = tree_param(t, i);
+ type_t param_types[n_overloads];
+
for (int j = 0; j < n_overloads; j++) {
- if (overloads[j] != NULL)
- type_set_add(type_param(tree_type(overloads[j]), i));
+ if (overloads[j] != NULL) {
+ param_types[j] = sem_find_param_type(p, overloads[j]);
+ if (param_types[j] != NULL)
+ type_set_add(param_types[j]);
+ }
}
- param_t p = tree_param(t, i);
- assert(p.kind == P_POS);
bool ok = sem_check(p.value);
type_set_pop();
@@ -2383,10 +2417,11 @@ static bool sem_resolve_overload(tree_t t, tree_t *pick, int *matches,
// Did argument types match for this overload?
bool match = true;
bool all_universal = true;
- type_t func_type = tree_type(overloads[n]);
- for (unsigned i = 0; i < tree_params(t); i++) {
- type_t ptype = tree_type(tree_param(t, i).value);
- match = match && type_eq(type_param(func_type, i), ptype);
+ for (int i = 0; i < nparams; i++) {
+ param_t p = tree_param(t, i);
+ type_t ptype = tree_type(p.value);
+ type_t mtype = sem_find_param_type(p, overloads[n]);
+ match = match && type_eq(mtype, ptype);
all_universal = all_universal && type_is_universal(ptype);
}
@@ -2397,7 +2432,7 @@ static bool sem_resolve_overload(tree_t t, tree_t *pick, int *matches,
// If all the arguments are universal integer or real and
// this is a builtin function then it doesn't matter which
// overload we pick as it will be constant-folded later
- type_t f_result = type_result(func_type);
+ type_t f_result = type_result(tree_type(overloads[n]));
switch (type_kind(f_result)) {
case T_INTEGER:
tree_set_type(t, type_universal_int());
@@ -2465,18 +2500,51 @@ static void sem_copy_default_args(tree_t call, tree_t decl)
}
}
+static bool sem_check_params(tree_t t)
+{
+ bool have_named = false;
+ const int nparams = tree_params(t);
+ for (int i = 0; i < nparams; i++) {
+ param_t p = tree_param(t, i);
+
+ switch (p.kind) {
+ case P_POS:
+ if (have_named)
+ sem_error(p.value, "positional parameters must precede named "
+ "parameters");
+ break;
+
+ case P_NAMED:
+ for (int j = 0; j < i; j++) {
+ param_t q = tree_param(t, j);
+ if ((q.kind == P_NAMED) && (q.name == p.name))
+ sem_error(p.value, "duplicate parameter name %s", istr(p.name));
+ }
+
+ have_named = true;
+ break;
+ }
+ }
+
+ return true;
+}
+
static bool sem_check_fcall(tree_t t)
{
+ if (!sem_check_params(t))
+ return false;
+
tree_t overloads[MAX_OVERLOADS];
int n_overloads = 0;
tree_t decl;
- int n = 0;
+ int n = 0, found_func = 0;
do {
if ((decl = scope_find_nth(tree_ident(t), n++))) {
switch (tree_kind(decl)) {
case T_FUNC_DECL:
case T_FUNC_BODY:
+ found_func++;
break;
case T_TYPE_DECL:
tree_change_kind(t, T_TYPE_CONV);
@@ -2521,7 +2589,10 @@ static bool sem_check_fcall(tree_t t)
} while (decl != NULL);
if (n_overloads == 0)
- sem_error(t, "undefined identifier %s", istr(tree_ident(t)));
+ sem_error(t, (found_func > 0
+ ? "no matching function %s"
+ : "undefined identifier %s"),
+ istr(tree_ident(t)));
int matches;
if (!sem_resolve_overload(t, &decl, &matches, overloads, n_overloads))
@@ -2590,16 +2661,20 @@ static bool sem_check_fcall(tree_t t)
static bool sem_check_pcall(tree_t t)
{
+ if (!sem_check_params(t))
+ return false;
+
tree_t overloads[MAX_OVERLOADS];
int n_overloads = 0;
tree_t decl;
- int n = 0;
+ int n = 0, found_proc = 0;
do {
if ((decl = scope_find_nth(tree_ident2(t), n++))) {
switch (tree_kind(decl)) {
case T_PROC_DECL:
case T_PROC_BODY:
+ found_proc++;
break;
default:
continue; // Look for the next matching name
@@ -2615,7 +2690,10 @@ static bool sem_check_pcall(tree_t t)
} while (decl != NULL);
if (n_overloads == 0)
- sem_error(t, "undefined procedure %s", istr(tree_ident2(t)));
+ sem_error(t, (found_proc > 0
+ ? "no matching procedure %s"
+ : "undefined procedure %s"),
+ istr(tree_ident2(t)));
int matches;
if (!sem_resolve_overload(t, &decl, &matches, overloads, n_overloads))
@@ -2629,7 +2707,7 @@ static bool sem_check_pcall(tree_t t)
char *p = buf;
const char *end = buf + sizeof(buf);
- for (int n = 0; n < n_overloads; n++) {
+ for (int n = 0; (n < n_overloads) && (p < end); n++) {
if (overloads[n] != NULL)
p += snprintf(p, end - p, "\n %s",
type_pp(tree_type(overloads[n])));
@@ -3520,9 +3598,6 @@ static bool sem_check_map(tree_t t, tree_t unit,
sem_error(p.value, "%s has no formal %s",
istr(tree_ident(unit)), istr(p.name));
break;
-
- case P_RANGE:
- sem_error(p.value, "ranges cannot be used here");
}
ok = sem_check_constrained(p.value, tree_type(decl)) && ok;
View
31 src/tree.c
@@ -686,7 +686,7 @@ param_t tree_param(tree_t t, unsigned n)
void tree_add_param(tree_t t, param_t e)
{
- assert(e.kind == P_RANGE || IS_EXPR(e.value));
+ assert(IS_EXPR(e.value));
if (e.kind == P_POS)
e.pos = tree_params(t);
@@ -706,7 +706,7 @@ param_t tree_genmap(tree_t t, unsigned n)
void tree_add_genmap(tree_t t, param_t e)
{
- assert(e.kind == P_RANGE || IS_EXPR(e.value));
+ assert(IS_EXPR(e.value));
if (e.kind == P_POS)
e.pos = tree_genmaps(t);
@@ -1052,11 +1052,6 @@ static void tree_visit_p(param_array_t *a, tree_visit_ctx_t *ctx)
{
for (unsigned i = 0; i < a->count; i++) {
switch (a->items[i].kind) {
- case P_RANGE:
- tree_visit_aux(a->items[i].range.left, ctx);
- tree_visit_aux(a->items[i].range.right, ctx);
- break;
-
case P_POS:
case P_NAMED:
tree_visit_aux(a->items[i].value, ctx);
@@ -1323,11 +1318,6 @@ static void write_p(param_array_t *a, tree_wr_ctx_t ctx)
write_u16(a->items[i].pos, ctx->file);
tree_write(a->items[i].value, ctx);
break;
- case P_RANGE:
- write_u16(a->items[i].range.kind, ctx->file);
- tree_write(a->items[i].range.left, ctx);
- tree_write(a->items[i].range.right, ctx);
- break;
case P_NAMED:
ident_write(a->items[i].name, ctx->ident_ctx);
tree_write(a->items[i].value, ctx);
@@ -1347,11 +1337,6 @@ static void read_p(param_array_t *a, tree_rd_ctx_t ctx)
a->items[i].pos = read_u16(ctx->file);
a->items[i].value = tree_read(ctx);
break;
- case P_RANGE:
- a->items[i].range.kind = read_u16(ctx->file);
- a->items[i].range.left = tree_read(ctx);
- a->items[i].range.right = tree_read(ctx);
- break;
case P_NAMED:
a->items[i].name = ident_read(ctx->ident_ctx);
a->items[i].value = tree_read(ctx);
@@ -1824,13 +1809,6 @@ static void rewrite_p(param_array_t *a, struct rewrite_ctx *ctx)
{
for (size_t i = 0; i < a->count; i++) {
switch (a->items[i].kind) {
- case P_RANGE:
- a->items[i].range.left =
- tree_rewrite_aux(a->items[i].range.left, ctx);
- a->items[i].range.right =
- tree_rewrite_aux(a->items[i].range.right, ctx);
- break;
-
case P_POS:
case P_NAMED:
a->items[i].value = tree_rewrite_aux(a->items[i].value, ctx);
@@ -2005,11 +1983,6 @@ static void copy_p(param_array_t *from, param_array_t *to,
tp->pos = fp->pos;
tp->value = tree_copy_aux(fp->value, ctx);
break;
- case P_RANGE:
- tp->range.kind = fp->range.kind;
- tp->range.left = tree_copy_aux(fp->range.left, ctx);
- tp->range.right = tree_copy_aux(fp->range.right, ctx);
- break;
case P_NAMED:
tp->name = fp->name;
tp->value = tree_copy_aux(fp->value, ctx);
View
3  src/tree.h
@@ -126,11 +126,10 @@ typedef struct assoc {
typedef struct param {
tree_t value;
union {
- range_t range; // P_RANGE
ident_t name; // P_NAME
unsigned pos; // P_POS
};
- enum { P_POS, P_NAMED, P_RANGE } kind;
+ enum { P_POS, P_NAMED } kind;
} param_t;
typedef struct context {
View
12 test/sem/func.vhd
@@ -107,4 +107,16 @@ package body func is
return default2;
end function;
+ function test10(k : in integer) return integer is
+ variable v : integer;
+ variable u : uenum;
+ begin
+ v := sum(x => 4, 1); -- Error
+ v := sum(1, x => 4, x => 4); -- Error
+ v := sum(1, y => k, x => 4); -- OK
+ u := resolved3(A, x => 4); -- OK
+ u := resolved3(x => 3, v => B); -- OK
+ return v;
+ end function;
+
end package body;
View
14 test/sem/procedure.vhd
@@ -50,4 +50,18 @@ package body p is
begin
end procedure;
+ procedure diff_types(x : in integer; y : in string) is
+ begin
+ end procedure;
+
+ procedure test_named is
+ begin
+ diff_types(1, "foo"); -- OK
+ diff_types(1, y => "bar"); -- OK
+ diff_types(x => 1, y => "foo"); -- OK
+ diff_types(y => "la", x => 6); -- OK
+ diff_types(y => "foo"); -- Error
+ diff_types(y => "f", 6); -- Error
+ end procedure;
+
end package body;
View
26 test/test_sem.c
@@ -443,17 +443,19 @@ START_TEST(test_func)
fail_unless(input_from_file(TESTDIR "/sem/func.vhd"));
const error_t expect[] = {
- { 5, "function arguments must have mode IN" },
- { 17, "must be an unconstrained array type" },
- { 21, "resolution function must have single argument" },
- { 25, "declaration UENUM is not a function" },
- { 27, "type of default value universal integer does not" },
- { 29, "subprogram body is not allowed in package specification" },
- { 36, "unit WORK.BAD not found in library WORK" },
- { 48, "no suitable overload for identifier A" },
- { 51, "function arguments must have mode IN" },
- { 56, "function must contain a return statement" },
- { 62, "duplicate declaration of function FOO" },
+ { 5, "function arguments must have mode IN" },
+ { 17, "must be an unconstrained array type" },
+ { 21, "resolution function must have single argument" },
+ { 25, "declaration UENUM is not a function" },
+ { 27, "type of default value universal integer does not" },
+ { 29, "subprogram body is not allowed in package specification" },
+ { 36, "unit WORK.BAD not found in library WORK" },
+ { 48, "no suitable overload for identifier A" },
+ { 51, "function arguments must have mode IN" },
+ { 56, "function must contain a return statement" },
+ { 62, "duplicate declaration of function FOO" },
+ { 114, "positional parameters must precede named parameters" },
+ { 115, "duplicate parameter name X" },
{ -1, NULL }
};
expect_errors(expect);
@@ -715,6 +717,8 @@ START_TEST(test_procedure)
{ 28, "cannot return a value from a procedure" },
{ 45, "type of default value universal integer does not match" },
{ 49, "argument Y without default follows arguments with" },
+ { 63, "no matching procedure DIFF_TYPES" },
+ { 64, "positional parameters must precede named parameters" },
{ -1, NULL }
};
expect_errors(expect);
Please sign in to comment.
Something went wrong with that request. Please try again.