Repository: JuliaLang/julia
File: src/module.c (C)

Code before:
        // we must have implicitly imported this with using, so call jl_binding_dbgmodule to try to get the name of the module we got this from
        jl_errorf("invalid method definition in %s: exported function %s.%s does not exist",
                    jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
    }
    int istype = f && jl_is_type(f);
    if (!istype) {
        if (kind == BINDING_KIND_IMPLICIT) {
            check_safe_newbinding(m, var);
            return b;
        }
        else if (kind != BINDING_KIND_IMPORTED) {
            // TODO: we might want to require explicitly importing types to add constructors
            //       or we might want to drop this error entirely
            jl_module_t *from = jl_binding_dbgmodule(b, m, var);
            jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended",
                        jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
        }
    }
    else if (kind != BINDING_KIND_IMPORTED) {
        int should_error = strcmp(jl_symbol_name(var), "=>") == 0;
        jl_module_t *from = jl_binding_dbgmodule(b, m, var);
        if (should_error)
            jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended",
                        jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
        else
            jl_printf(JL_STDERR, "WARNING: Type %s.%s was auto-`import`ed in `%s`.\n"
                                 "NOTE: This behavior is deprecated and may error in future Julia versions.\n"
                                 "NOTE: This behavior may have differed in Julia versions prior to 1.12 depending on binding resolution."
                                 "Hint: To retain the current behavior, add an explicit `import %s: %s`\n"
                                 "Hint: To create a new generic function of the same name use `function %s end`.\n",
                jl_module_debug_name(from), jl_symbol_name(var),
                jl_module_debug_name(m),
                jl_module_debug_name(from), jl_symbol_name(var),
                jl_symbol_name(var));
    }
    return ownerb;
}

// for error message printing: look up the module that exported a binding to m as var
// this might not be the same as the owner of the binding, since the binding itself may itself have been imported from elsewhere
static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var)
{
    jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
    jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction);
    if (jl_bkind_is_some_import(decode_restriction_kind(pku))) {
        return ((jl_binding_t*)decode_restriction_value(pku))->globalref->mod;
    }
    return m;
}

static void jl_binding_dep_message(jl_module_t *m, jl_sym_t *name, jl_binding_t *b);

Review comment (suggestion):
If I'm a user who wrote `String(x) = 1` or whatever and got this warning, I don't think I'd make the connection that the problem was actually because I was extending a type constructor without qualification. Can that be made more explicit? Also, it could be worthwhile to encourage qualification for extension in the message rather than (or at least in addition to) implicit extension via `import`.

Code after:
        // we must have implicitly imported this with using, so call jl_binding_dbgmodule to try to get the name of the module we got this from
        jl_errorf("invalid method definition in %s: exported function %s.%s does not exist",
                    jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
    }
    int istype = f && jl_is_type(f);
    if (!istype) {
        if (kind == BINDING_KIND_IMPLICIT) {
            check_safe_newbinding(m, var);
            return b;
        }
        else if (kind != BINDING_KIND_IMPORTED) {
            // TODO: we might want to require explicitly importing types to add constructors
            //       or we might want to drop this error entirely
            jl_module_t *from = jl_binding_dbgmodule(b, m, var);
            jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended",
                        jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
        }
    }
    else if (kind != BINDING_KIND_IMPORTED) {
        int should_error = strcmp(jl_symbol_name(var), "=>") == 0;
        jl_module_t *from = jl_binding_dbgmodule(b, m, var);
        if (should_error)
            jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended",
                        jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var));
        else
            jl_printf(JL_STDERR, "WARNING: Constructor for type \"%s\" was extended in `%s` without explicit qualification or import.\n"
                                 "  NOTE: Assumed \"%s\" refers to `%s.%s`. This behavior is deprecated and may differ in future versions.`\n"
                                 "  NOTE: This behavior may have differed in Julia versions prior to 1.12.\n"
                                 "  Hint: If you intended to create a new generic function of the same name, use `function %s end`.\n"
                                 "  Hint: To silence the warning, qualify `%s` as `%s.%s` or explicitly `import %s: %s`\n",
                jl_symbol_name(var), jl_module_debug_name(m),
                jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var),
                jl_symbol_name(var), jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var),
                jl_module_debug_name(from), jl_symbol_name(var));
    }
    return ownerb;
}

// for error message printing: look up the module that exported a binding to m as var
// this might not be the same as the owner of the binding, since the binding itself may itself have been imported from elsewhere
static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var)
{
    jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
    jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction);
    if (jl_bkind_is_some_import(decode_restriction_kind(pku))) {
        return ((jl_binding_t*)decode_restriction_value(pku))->globalref->mod;
    }
    return m;
}

static void jl_binding_dep_message(jl_module_t *m, jl_sym_t *name, jl_binding_t *b);