Skip to content

Commit 5e3e8fb

Browse files
committed
Soft deprecation of LoadError in runtime
Remove use of LoadError from the runtime now that backtraces are more reliable. It's left in boot.jl for now for 1.x compatibility. Compatibility: It's difficult to deprecate this in a fully backward compatible way, because packages commonly test macro expansion using constructs like @ test_throws LoadError macroexpand(:(@ some_pkg_macro)) to make this into as minor a change as possible, grandfather special rules for LoadError into stdlib/Test.
1 parent 294b866 commit 5e3e8fb

File tree

17 files changed

+84
-152
lines changed

17 files changed

+84
-152
lines changed

base/boot.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ AssertionError() = AssertionError("")
306306

307307
abstract type WrappedException <: Exception end
308308

309+
# Usage of LoadError is deprecated in the runtime. It's left here for compatibility.
309310
struct LoadError <: WrappedException
310311
file::AbstractString
311312
line::Int

base/docs/basedocs.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,9 @@ AssertionError
19141914
19151915
An error occurred while [`include`](@ref Base.include)ing, [`require`](@ref Base.require)ing, or [`using`](@ref) a file. The error specifics
19161916
should be available in the `.error` field.
1917+
1918+
!!! compat "Julia 1.3"
1919+
LoadError is deprecated because it is no longer emitted by the runtime as of Julia 1.3.
19171920
"""
19181921
LoadError
19191922

src/ast.c

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -889,11 +889,7 @@ jl_value_t *jl_parse_eval_all(const char *fname,
889889
ctx->module = old_module;
890890
jl_ast_ctx_leave(ctx);
891891
if (err) {
892-
if (jl_loaderror_type == NULL)
893-
jl_rethrow();
894-
else
895-
jl_throw(jl_new_struct(jl_loaderror_type, form, result,
896-
jl_current_exception()));
892+
jl_rethrow();
897893
}
898894
JL_GC_POP();
899895
return result;
@@ -1028,32 +1024,14 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule
10281024
size_t world = jl_world_counter;
10291025
ptls->world_age = world;
10301026
jl_value_t *result;
1031-
JL_TRY {
1032-
margs[0] = jl_toplevel_eval(*ctx, margs[0]);
1033-
jl_method_instance_t *mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1, world);
1034-
if (mfunc == NULL) {
1035-
jl_method_error((jl_function_t*)margs[0], margs, nargs, world);
1036-
// unreachable
1037-
}
1038-
*ctx = mfunc->def.method->module;
1039-
result = jl_invoke(mfunc, margs, nargs);
1040-
}
1041-
JL_CATCH {
1042-
if (jl_loaderror_type == NULL) {
1043-
jl_rethrow();
1044-
}
1045-
else {
1046-
jl_value_t *lno = margs[1];
1047-
jl_value_t *file = jl_fieldref(lno, 1);
1048-
if (jl_is_symbol(file))
1049-
margs[0] = jl_cstr_to_string(jl_symbol_name((jl_sym_t*)file));
1050-
else
1051-
margs[0] = jl_cstr_to_string("<macrocall>");
1052-
margs[1] = jl_fieldref(lno, 0); // extract and allocate line number
1053-
jl_throw(jl_new_struct(jl_loaderror_type, margs[0], margs[1],
1054-
jl_current_exception()));
1055-
}
1027+
margs[0] = jl_toplevel_eval(*ctx, margs[0]);
1028+
jl_method_instance_t *mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1, world);
1029+
if (mfunc == NULL) {
1030+
jl_method_error((jl_function_t*)margs[0], margs, nargs, world);
1031+
// unreachable
10561032
}
1033+
*ctx = mfunc->def.method->module;
1034+
result = jl_invoke(mfunc, margs, nargs);
10571035
ptls->world_age = last_age;
10581036
JL_GC_POP();
10591037
return result;

src/init.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,6 @@ void jl_get_builtin_hooks(void)
902902
#endif
903903
jl_argumenterror_type = (jl_datatype_t*)core("ArgumentError");
904904
jl_methoderror_type = (jl_datatype_t*)core("MethodError");
905-
jl_loaderror_type = (jl_datatype_t*)core("LoadError");
906905
jl_initerror_type = (jl_datatype_t*)core("InitError");
907906

908907
jl_weakref_type = (jl_datatype_t*)core("WeakRef");

src/jltypes.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ jl_datatype_t *jl_errorexception_type;
108108
jl_datatype_t *jl_argumenterror_type;
109109
jl_datatype_t *jl_typeerror_type;
110110
jl_datatype_t *jl_methoderror_type;
111-
jl_datatype_t *jl_loaderror_type;
112111
jl_datatype_t *jl_initerror_type;
113112
jl_datatype_t *jl_undefvarerror_type;
114113
jl_datatype_t *jl_lineinfonode_type;

src/julia.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,6 @@ extern JL_DLLEXPORT jl_datatype_t *jl_abstractstring_type JL_GLOBALLY_ROOTED;
586586
extern JL_DLLEXPORT jl_datatype_t *jl_string_type JL_GLOBALLY_ROOTED;
587587
extern JL_DLLEXPORT jl_datatype_t *jl_errorexception_type JL_GLOBALLY_ROOTED;
588588
extern JL_DLLEXPORT jl_datatype_t *jl_argumenterror_type JL_GLOBALLY_ROOTED;
589-
extern JL_DLLEXPORT jl_datatype_t *jl_loaderror_type JL_GLOBALLY_ROOTED;
590589
extern JL_DLLEXPORT jl_datatype_t *jl_initerror_type JL_GLOBALLY_ROOTED;
591590
extern JL_DLLEXPORT jl_datatype_t *jl_typeerror_type JL_GLOBALLY_ROOTED;
592591
extern JL_DLLEXPORT jl_datatype_t *jl_methoderror_type JL_GLOBALLY_ROOTED;

src/rtutils.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -932,15 +932,6 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt
932932
}
933933
n += jl_printf(out, "]");
934934
}
935-
else if (vt == jl_loaderror_type) {
936-
n += jl_printf(out, "LoadError(at ");
937-
n += jl_static_show_x(out, *(jl_value_t**)v, depth);
938-
// Access the field directly to avoid allocation
939-
n += jl_printf(out, " line %" PRIdPTR, ((intptr_t*)v)[1]);
940-
n += jl_printf(out, ": ");
941-
n += jl_static_show_x(out, ((jl_value_t**)v)[2], depth);
942-
n += jl_printf(out, ")");
943-
}
944935
else if (vt == jl_errorexception_type) {
945936
n += jl_printf(out, "ErrorException(");
946937
n += jl_static_show_x(out, *(jl_value_t**)v, depth);

stdlib/Printf/test/runtests.jl

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,6 @@
22

33
using Test, Printf
44

5-
# this macro tests for exceptions thrown at macro expansion
6-
macro test_me(ty, ex)
7-
return quote
8-
@test_throws $(esc(ty)) try
9-
$(esc(ex))
10-
catch err
11-
@test err isa LoadError
12-
@test err.file === $(string(__source__.file))
13-
@test err.line === $(__source__.line)
14-
rethrow(err.error)
15-
end
16-
end
17-
end
18-
195
# printf
206
# int
217
@test (@sprintf "%d" typemax(Int64)) == "9223372036854775807"
@@ -205,14 +191,14 @@ end
205191
# escape %
206192
@test (@sprintf "%%") == "%"
207193
@test (@sprintf "%%s") == "%s"
208-
@test_me ArgumentError("invalid printf format string: \"%\"") @macroexpand(@sprintf "%") #" (fixes syntax highlighting)
194+
@test_throws ArgumentError("invalid printf format string: \"%\"") @macroexpand(@sprintf "%") #" (fixes syntax highlighting)
209195

210196
# argument count
211-
@test_me ArgumentError("@sprintf: wrong number of arguments (0) should be (1)") @macroexpand(@sprintf "%s")
212-
@test_me ArgumentError("@sprintf: wrong number of arguments (2) should be (1)") @macroexpand(@sprintf "%s" "1" "2")
197+
@test_throws ArgumentError("@sprintf: wrong number of arguments (0) should be (1)") @macroexpand(@sprintf "%s")
198+
@test_throws ArgumentError("@sprintf: wrong number of arguments (2) should be (1)") @macroexpand(@sprintf "%s" "1" "2")
213199

214200
# no interpolation
215-
@test_me ArgumentError("@sprintf: format must be a plain static string (no interpolation or prefix)") @macroexpand(@sprintf "$n")
201+
@test_throws ArgumentError("@sprintf: format must be a plain static string (no interpolation or prefix)") @macroexpand(@sprintf "$n")
216202

217203
# type width specifier parsing (ignored)
218204
@test (@sprintf "%llf" 1.2) == "1.200000"
@@ -258,7 +244,7 @@ end
258244
# invalid format specifiers, not "diouxXDOUeEfFgGaAcCsSpn"
259245
for c in "bBhHIjJkKlLmMNPqQrRtTvVwWyYzZ"
260246
fmt_str = string("%", c)
261-
@test_me ArgumentError("@sprintf: first argument must be a format string") @macroexpand(@sprintf $fmt_str 1)
247+
@test_throws ArgumentError("@sprintf: first argument must be a format string") @macroexpand(@sprintf $fmt_str 1)
262248
end
263249

264250
# combo
@@ -271,7 +257,7 @@ end
271257
@test (@sprintf "%s %s %s %d %d %d %f %f %f" Any[10^x+y for x=1:3,y=1:3 ]...) == "11 101 1001 12 102 1002 13.000000 103.000000 1003.000000"
272258

273259
# @printf
274-
@test_me ArgumentError("@printf: first or second argument must be a format string") @macroexpand(@printf 1)
260+
@test_throws ArgumentError("@printf: first or second argument must be a format string") @macroexpand(@printf 1)
275261

276262
# Check bug with trailing nul printing BigFloat
277263
@test (@sprintf("%.330f", BigFloat(1)))[end] != '\0'
@@ -286,10 +272,10 @@ end
286272
@test (@sprintf("%d\u0f00%d", 1, 2)) == "1\u0f002"
287273
@test (@sprintf("%d\U0001ffff%d", 1, 2)) == "1\U0001ffff2"
288274
@test (@sprintf("%d\u2203%d\u0203", 1, 2)) == "1\u22032\u0203"
289-
@test_me ArgumentError @macroexpand(@sprintf("%y%d", 1, 2))
290-
@test_me ArgumentError @macroexpand(@sprintf("%\u00d0%d", 1, 2))
291-
@test_me ArgumentError @macroexpand(@sprintf("%\u0f00%d", 1, 2))
292-
@test_me ArgumentError @macroexpand(@sprintf("%\U0001ffff%d", 1, 2))
275+
@test_throws ArgumentError @macroexpand(@sprintf("%y%d", 1, 2))
276+
@test_throws ArgumentError @macroexpand(@sprintf("%\u00d0%d", 1, 2))
277+
@test_throws ArgumentError @macroexpand(@sprintf("%\u0f00%d", 1, 2))
278+
@test_throws ArgumentError @macroexpand(@sprintf("%\U0001ffff%d", 1, 2))
293279

294280
# test at macro execution time
295281
@test_throws ArgumentError("@sprintf: wrong number of arguments (2) should be (3)") (@sprintf "%d%d%d" 1:2...)

stdlib/Test/src/Test.jl

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -577,18 +577,24 @@ end
577577

578578
# An internal function, called by the code generated by @test_throws
579579
# to evaluate and catch the thrown exception - if it exists
580-
function do_test_throws(result::ExecutionResult, @nospecialize(orig_expr), @nospecialize(extype))
580+
function do_test_throws(result::ExecutionResult, @nospecialize(orig_expr), @nospecialize(expected_exc))
581581
if isa(result, Threw)
582582
# Check that the right type of exception was thrown
583583
success = false
584584
exc = result.exception
585-
if isa(extype, Type)
586-
success = isa(exc, extype)
585+
# NB: The use of LoadError in Base is deprecated, but in order to limit
586+
# the breakage in package tests we add extra logic here.
587+
if isa(expected_exc, Type)
588+
success = isa(exc, expected_exc) ||
589+
(expected_exc == LoadError && exc isa Exception) # deprecated
587590
else
588-
if isa(exc, typeof(extype))
591+
if expected_exc isa LoadError && !(exc isa LoadError) && typeof(expected_exc.error) == typeof(exc)
592+
expected_exc = expected_exc.error # deprecated
593+
end
594+
if exc isa typeof(expected_exc)
589595
success = true
590-
for fld in 1:nfields(extype)
591-
if !isequal(getfield(extype, fld), getfield(exc, fld))
596+
for fld in 1:nfields(expected_exc)
597+
if !isequal(getfield(expected_exc, fld), getfield(exc, fld))
592598
success = false
593599
break
594600
end
@@ -598,10 +604,10 @@ function do_test_throws(result::ExecutionResult, @nospecialize(orig_expr), @nosp
598604
if success
599605
testres = Pass(:test_throws, nothing, nothing, exc)
600606
else
601-
testres = Fail(:test_throws_wrong, orig_expr, extype, exc, result.source)
607+
testres = Fail(:test_throws_wrong, orig_expr, expected_exc, exc, result.source)
602608
end
603609
else
604-
testres = Fail(:test_throws_nothing, orig_expr, extype, nothing, result.source)
610+
testres = Fail(:test_throws_nothing, orig_expr, expected_exc, nothing, result.source)
605611
end
606612
record(get_testset(), testres)
607613
end

stdlib/Test/test/runtests.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,3 +915,10 @@ end
915915
end
916916
end
917917

918+
@testset "Soft deprecation of @test_throws LoadError expr" begin
919+
# Undecorated LoadError can stand in for the wrapped error (ie, any Exception)
920+
@test_throws LoadError throw(ErrorException("Real error"))
921+
# Expected LoadError instances are unwrapped as necessary
922+
@test_throws LoadError("file", 111, ErrorException("Real error")) throw(ErrorException("Real error"))
923+
@test_throws LoadError("file", 111, ErrorException("Real error")) LoadError("file", 111, throw(ErrorException("Real error")))
924+
end

0 commit comments

Comments
 (0)