Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport: nested function name canonicalization #179

Open
wants to merge 3 commits into
base: v1.10.2+RAI
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,12 @@ syntaxes:

```jldoctest
julia> x -> x^2 + 2x - 1
#1 (generic function with 1 method)
#2 (generic function with 1 method)

julia> function (x)
x^2 + 2x - 1
end
#3 (generic function with 1 method)
#5 (generic function with 1 method)
```

This creates a function taking one argument `x` and returning the value of the polynomial `x^2 +
Expand Down
44 changes: 40 additions & 4 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef _OS_WINDOWS_
#include <malloc.h>
#endif
Expand Down Expand Up @@ -160,11 +161,46 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint
return (b != NULL && jl_atomic_load_relaxed(&b->owner) == b) ? fl_ctx->T : fl_ctx->F;
}

static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT
// Used to generate a unique suffix for a given symbol (e.g. variable or type name)
// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp.
// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes
// of the form $top_level_method_name##$counter, where `counter` is the smallest integer
// such that the resulting name is not already defined in the current module's bindings.
// If the top of the stack is NIL, we simply return the current module's counter.
// This ensures that precompile statements are a bit more stable across different versions
// of a codebase. see #53719
static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
{
argcount(fl_ctx, "julia-module-unique-name", nargs, 1);
jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx);
assert(ctx->module);
return fixnum(jl_module_next_counter(ctx->module));
jl_module_t *m = ctx->module;
assert(m != NULL);
// Get the outermost function name from the `parsed_method_stack` top
char *funcname = NULL;
value_t parsed_method_stack = args[0];
if (parsed_method_stack != fl_ctx->NIL) {
value_t bottom_stack_symbol = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "last")), parsed_method_stack);
funcname = tosymbol(fl_ctx, bottom_stack_symbol, "julia-module-unique-name")->name;
}
size_t sz = funcname != NULL ? strlen(funcname) + 32 : 32; // 32 is enough for the suffix
char *buf = (char*)alloca(sz);
if (funcname != NULL && strchr(funcname, '#') == NULL) {
for (int i = 0; ; i++) {
snprintf(buf, sz, "%s##%d", funcname, i);
jl_sym_t *sym = jl_symbol(buf);
JL_LOCK(&m->lock);
if (jl_get_module_binding(m, sym, 0) == NULL) { // make sure this name is not already taken
jl_get_module_binding(m, sym, 1); // create the binding
JL_UNLOCK(&m->lock);
return symbol(fl_ctx, buf);
}
JL_UNLOCK(&m->lock);
}
}
else {
snprintf(buf, sz, "%d", jl_module_next_counter(m));
}
return symbol(fl_ctx, buf);
}

static value_t fl_julia_current_file(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT
Expand Down Expand Up @@ -206,7 +242,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m

static const builtinspec_t julia_flisp_ast_ext[] = {
{ "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint
{ "current-julia-module-counter", fl_current_module_counter },
{ "current-julia-module-counter", fl_module_unique_name },
{ "julia-scalar?", fl_julia_scalar },
{ "julia-current-file", fl_julia_current_file },
{ "julia-current-line", fl_julia_current_line },
Expand Down
22 changes: 6 additions & 16 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,21 @@ extern "C" {

// allocating TypeNames -----------------------------------------------------------

static int is10digit(char c) JL_NOTSAFEPOINT
{
return (c >= '0' && c <= '9');
}

static jl_sym_t *jl_demangle_typename(jl_sym_t *s) JL_NOTSAFEPOINT
{
char *n = jl_symbol_name(s);
if (n[0] != '#')
return s;
char *end = strrchr(n, '#');
char *end = strchr(&n[1], '#');
// handle `#f...##...#...`
if (end != NULL && end[1] == '#')
end = strchr(&end[2], '#');
int32_t len;
if (end == n || end == n+1)
if (end == NULL || end == n+1)
len = strlen(n) - 1;
else
len = (end-n) - 1; // extract `f` from `#f#...`
if (is10digit(n[1]))
if (isdigit(n[1]) || is_canonicalized_anonfn_typename(n))
return _jl_symbol(n, len+1);
return _jl_symbol(&n[1], len);
}
Expand Down Expand Up @@ -687,14 +685,6 @@ void jl_compute_field_offsets(jl_datatype_t *st)
return;
}

static int is_anonfn_typename(char *name)
{
if (name[0] != '#' || name[1] == '#')
return 0;
char *other = strrchr(name, '#');
return other > &name[1] && is10digit(other[1]);
}

JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
jl_sym_t *name,
jl_module_t *module,
Expand Down
2 changes: 1 addition & 1 deletion src/flisp/flisp.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ value_t fl_cons(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT;
value_t fl_list2(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT;
value_t fl_listn(fl_context_t *fl_ctx, size_t n, ...) JL_NOTSAFEPOINT;
value_t symbol(fl_context_t *fl_ctx, const char *str) JL_NOTSAFEPOINT;
char *symbol_name(fl_context_t *fl_ctx, value_t v);
char *symbol_name(fl_context_t *fl_ctx, value_t v) JL_NOTSAFEPOINT;
int fl_is_keyword_name(const char *str, size_t len);
value_t alloc_vector(fl_context_t *fl_ctx, size_t n, int init);
size_t llength(value_t v);
Expand Down
8 changes: 0 additions & 8 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1535,14 +1535,6 @@ void print_func_loc(JL_STREAM *s, jl_method_t *m)
}
}

static int is_anonfn_typename(char *name)
{
if (name[0] != '#' || name[1] == '#')
return 0;
char *other = strrchr(name, '#');
return other > &name[1] && other[1] > '0' && other[1] <= '9';
}

static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue)
{
// method overwritten
Expand Down
Loading