From d6dd7eee25b0e9ed5fa50da7d8ec10709f75fc00 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 17 May 2024 16:01:41 +0530 Subject: [PATCH 01/19] Update errorshow.jl error hint for getproperty(::Dict, ::Symbol) addresses #53618 --- base/boot.jl | 7 ++++++- base/dict.jl | 8 ++++++++ base/errorshow.jl | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/base/boot.jl b/base/boot.jl index 5d2527efd44c0..35095d768233d 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -206,7 +206,7 @@ export InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError, OverflowError, StackOverflowError, SegmentationFault, UndefRefError, UndefVarError, TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError, - UndefKeywordError, ConcurrencyViolationError, + UndefKeywordError, ConcurrencyViolationError, MemberAccessError, # AST representation Expr, QuoteNode, LineNumberNode, GlobalRef, # object model functions @@ -404,6 +404,11 @@ struct AssertionError <: Exception end AssertionError() = AssertionError("") +struct MemberAccessError <: Exception + objType::DataType + x::Symbol +end + abstract type WrappedException <: Exception end struct LoadError <: WrappedException diff --git a/base/dict.jl b/base/dict.jl index 4a63ed364b64d..b95d32960facd 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -116,6 +116,14 @@ Dict(ps::Pair...) = Dict(ps) Dict(kv) = dict_with_eltype((K, V) -> Dict{K, V}, kv, eltype(kv)) +function getproperty(d::Dict, x::Symbol) + if x in propertynames(d) + return getfield(d, x) + else + throw(MemberAccessError(typeof(d), x)) + end +end + empty(a::AbstractDict, ::Type{K}, ::Type{V}) where {K, V} = Dict{K, V}() # Gets 7 most significant bits from the hash (hsh), first bit is 1 diff --git a/base/errorshow.jl b/base/errorshow.jl index 567339c668600..939fd8c130b6a 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -367,6 +367,12 @@ function showerror(io::IO, ex::MethodError) nothing end +function showerror(io::IO, exc::MemberAccessError) + @nospecialize + println(io, "MemberAccessError : member access of this field on this DataType is not entertained.\n") + Base.Experimental.show_error_hints(io, exc) +end + striptype(::Type{T}) where {T} = T striptype(::Any) = nothing @@ -1086,6 +1092,33 @@ end Experimental.register_error_hint(methods_on_iterable, MethodError) +# Display a hint in case the use tries to access non-member fields of container type datastructures +function member_access_handler(io, exc) + @nospecialize + x = exc.x + objType = exc.objType + if objType <: Dict + println(io, + """ + The field `$x` is not a member of Dict type. In case you + are trying to access values using keys consider + using `indexing` operation. + Example: + ```julia + dict = Dict($(x)=>1) + dict[$(x)] + ``` + """) + else + println(io, """ + This datatype doesn't allow member access of this field-`$(x)` for end users. + Please refer to documentation on $(objType) on access rights and means to do it. + """) + end +end + +Experimental.register_error_hint(member_access_handler, MemberAccessError) + # ExceptionStack implementation size(s::ExceptionStack) = size(s.stack) getindex(s::ExceptionStack, i::Int) = s.stack[i] From af793bd08792726f59719db1bbe7e746055934e6 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 17 May 2024 16:23:54 +0530 Subject: [PATCH 02/19] formatting --- base/boot.jl | 4 ++-- base/dict.jl | 10 +++++----- base/errorshow.jl | 51 +++++++++++++++++++++++++---------------------- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 35095d768233d..8877f9e701896 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -405,8 +405,8 @@ end AssertionError() = AssertionError("") struct MemberAccessError <: Exception - objType::DataType - x::Symbol + objType::DataType + x::Symbol end abstract type WrappedException <: Exception end diff --git a/base/dict.jl b/base/dict.jl index b95d32960facd..bdf564732bc57 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -117,11 +117,11 @@ Dict(ps::Pair...) = Dict(ps) Dict(kv) = dict_with_eltype((K, V) -> Dict{K, V}, kv, eltype(kv)) function getproperty(d::Dict, x::Symbol) - if x in propertynames(d) - return getfield(d, x) - else - throw(MemberAccessError(typeof(d), x)) - end + if x in propertynames(d) + return getfield(d, x) + else + throw(MemberAccessError(typeof(d), x)) + end end empty(a::AbstractDict, ::Type{K}, ::Type{V}) where {K, V} = Dict{K, V}() diff --git a/base/errorshow.jl b/base/errorshow.jl index 939fd8c130b6a..82ec0323bcb34 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -368,9 +368,9 @@ function showerror(io::IO, ex::MethodError) end function showerror(io::IO, exc::MemberAccessError) - @nospecialize - println(io, "MemberAccessError : member access of this field on this DataType is not entertained.\n") - Base.Experimental.show_error_hints(io, exc) + @nospecialize + println(io, "MemberAccessError : member access of this field on this DataType is not entertained.\n") + Base.Experimental.show_error_hints(io, exc) end striptype(::Type{T}) where {T} = T @@ -1094,27 +1094,30 @@ Experimental.register_error_hint(methods_on_iterable, MethodError) # Display a hint in case the use tries to access non-member fields of container type datastructures function member_access_handler(io, exc) - @nospecialize - x = exc.x - objType = exc.objType - if objType <: Dict - println(io, - """ - The field `$x` is not a member of Dict type. In case you - are trying to access values using keys consider - using `indexing` operation. - Example: - ```julia - dict = Dict($(x)=>1) - dict[$(x)] - ``` - """) - else - println(io, """ - This datatype doesn't allow member access of this field-`$(x)` for end users. - Please refer to documentation on $(objType) on access rights and means to do it. - """) - end + @nospecialize + x = exc.x + objType = exc.objType + if objType <: Dict + println(io, + """ + The field `$x` is not a member of Dict type. In case you + are trying to access values using keys consider + using `indexing` operation. + Example: + ```julia + dict = Dict($(x)=>1) + dict[$(x)] + ``` + """ + ) + else + println(io, + """ + This datatype doesn't allow member access of this field-`$(x)` for end users. + Please refer to documentation on $(objType) on access rights and means to do it. + """ + ) + end end Experimental.register_error_hint(member_access_handler, MemberAccessError) From 2059bb6c14a0485cbc4f5c461d470093bb650141 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 17 May 2024 17:44:39 +0530 Subject: [PATCH 03/19] Update base/boot.jl: julian naming Co-authored-by: Lilith Orion Hafner --- base/boot.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 8877f9e701896..ff4f13776b0f1 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -404,9 +404,9 @@ struct AssertionError <: Exception end AssertionError() = AssertionError("") -struct MemberAccessError <: Exception - objType::DataType - x::Symbol +struct UndefFieldError <: Exception + type::DataType + field::Symbol end abstract type WrappedException <: Exception end From cb03f1c344e0afc481ad44bc74d8fd3d42ca7da4 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 17 May 2024 17:48:30 +0530 Subject: [PATCH 04/19] removing else case in Dict Hint Co-authored-by: Lilith Orion Hafner --- base/errorshow.jl | 7 ------- 1 file changed, 7 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 82ec0323bcb34..71ec55cd561d3 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1110,13 +1110,6 @@ function member_access_handler(io, exc) ``` """ ) - else - println(io, - """ - This datatype doesn't allow member access of this field-`$(x)` for end users. - Please refer to documentation on $(objType) on access rights and means to do it. - """ - ) end end From 297a3578c2fabe780ac17c0bd6e2a731f8b25020 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 17 May 2024 17:51:00 +0530 Subject: [PATCH 05/19] Update base/errorshow.jl for better julian naming convention Co-authored-by: Lilith Orion Hafner --- base/boot.jl | 4 ++-- base/dict.jl | 8 -------- base/errorshow.jl | 23 +++++++++++------------ src/datatype.c | 2 +- src/jl_exported_data.inc | 1 + src/jltypes.c | 1 + src/julia.h | 3 ++- src/rtutils.c | 4 ++-- src/staticdata.c | 3 ++- 9 files changed, 22 insertions(+), 27 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index ff4f13776b0f1..69fd58691dc6f 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -206,7 +206,7 @@ export InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError, OverflowError, StackOverflowError, SegmentationFault, UndefRefError, UndefVarError, TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError, - UndefKeywordError, ConcurrencyViolationError, MemberAccessError, + UndefKeywordError, ConcurrencyViolationError, FieldError, # AST representation Expr, QuoteNode, LineNumberNode, GlobalRef, # object model functions @@ -404,7 +404,7 @@ struct AssertionError <: Exception end AssertionError() = AssertionError("") -struct UndefFieldError <: Exception +struct FieldError <: Exception type::DataType field::Symbol end diff --git a/base/dict.jl b/base/dict.jl index bdf564732bc57..4a63ed364b64d 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -116,14 +116,6 @@ Dict(ps::Pair...) = Dict(ps) Dict(kv) = dict_with_eltype((K, V) -> Dict{K, V}, kv, eltype(kv)) -function getproperty(d::Dict, x::Symbol) - if x in propertynames(d) - return getfield(d, x) - else - throw(MemberAccessError(typeof(d), x)) - end -end - empty(a::AbstractDict, ::Type{K}, ::Type{V}) where {K, V} = Dict{K, V}() # Gets 7 most significant bits from the hash (hsh), first bit is 1 diff --git a/base/errorshow.jl b/base/errorshow.jl index 71ec55cd561d3..29e0c6e53cf0a 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -367,9 +367,9 @@ function showerror(io::IO, ex::MethodError) nothing end -function showerror(io::IO, exc::MemberAccessError) +function showerror(io::IO, exc::FieldError) @nospecialize - println(io, "MemberAccessError : member access of this field on this DataType is not entertained.\n") + println(io, "FieldError: type $(exc.type) has no field $(exc.field)") Base.Experimental.show_error_hints(io, exc) end @@ -1093,27 +1093,26 @@ end Experimental.register_error_hint(methods_on_iterable, MethodError) # Display a hint in case the use tries to access non-member fields of container type datastructures -function member_access_handler(io, exc) +function fielderror_hint_handler(io, exc) @nospecialize - x = exc.x - objType = exc.objType - if objType <: Dict + field = exc.field + type = exc.type + if type == :Dict println(io, """ - The field `$x` is not a member of Dict type. In case you - are trying to access values using keys consider - using `indexing` operation. + \nDid you mean to access dict values using key: `$field` ? + Consider using `indexing` operation. Example: ```julia - dict = Dict($(x)=>1) - dict[$(x)] + dict = Dict($(field)=>someValue) + dict[$(field)] ``` """ ) end end -Experimental.register_error_hint(member_access_handler, MemberAccessError) +Experimental.register_error_hint(fielderror_hint_handler, FieldError) # ExceptionStack implementation size(s::ExceptionStack) = size(s.stack) diff --git a/src/datatype.c b/src/datatype.c index abbec420bb617..1a4694a594510 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1736,7 +1736,7 @@ JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err) } } if (err) - jl_has_no_field_error(t->name->name, fld); + jl_has_no_field_error(t, fld); return -1; } diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index 79ff437841879..ff79966b2b01b 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -138,6 +138,7 @@ XX(jl_uint8_type) \ XX(jl_undefref_exception) \ XX(jl_undefvarerror_type) \ + XX(jl_fielderror_type) \ XX(jl_unionall_type) \ XX(jl_uniontype_type) \ XX(jl_upsilonnode_type) \ diff --git a/src/jltypes.c b/src/jltypes.c index 59807226fb4a9..37852dcb0004c 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3727,6 +3727,7 @@ void post_boot_hooks(void) jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError")); jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError")); jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError"); + jl_fielderror_type = (jl_datatype_t*)core("FieldError"); jl_atomicerror_type = (jl_datatype_t*)core("ConcurrencyViolationError"); jl_interrupt_exception = jl_new_struct_uninit((jl_datatype_t*)core("InterruptException")); jl_boundserror_type = (jl_datatype_t*)core("BoundsError"); diff --git a/src/julia.h b/src/julia.h index 6910167dae46d..ccd70bf01f23c 100644 --- a/src/julia.h +++ b/src/julia.h @@ -869,6 +869,7 @@ extern JL_DLLIMPORT jl_datatype_t *jl_initerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_typeerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_methoderror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_undefvarerror_type JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_fielderror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_atomicerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_missingcodeerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_lineinfonode_type JL_GLOBALLY_ROOTED; @@ -2024,7 +2025,7 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, jl_value_t *ty JL_MAYBE_UNROOTED, jl_value_t *got JL_MAYBE_UNROOTED); JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t *scope JL_MAYBE_UNROOTED); -JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_sym_t *type_name, jl_sym_t *var); +JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var); JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str); JL_DLLEXPORT void JL_NORETURN jl_bounds_error(jl_value_t *v JL_MAYBE_UNROOTED, jl_value_t *t JL_MAYBE_UNROOTED); diff --git a/src/rtutils.c b/src/rtutils.c index 7df3230755e63..4a2e5c230883e 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -152,9 +152,9 @@ JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t * jl_throw(jl_new_struct(jl_undefvarerror_type, var, scope)); } -JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_sym_t *type_name, jl_sym_t *var) +JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var) { - jl_errorf("type %s has no field %s", jl_symbol_name(type_name), jl_symbol_name(var)); + jl_throw(jl_new_struct(jl_fielderror_type, t, var)); } JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str) // == jl_exceptionf(jl_atomicerror_type, "%s", str) diff --git a/src/staticdata.c b/src/staticdata.c index 28051d52eb105..ea2fac6c0fce6 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -100,7 +100,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 190 +#define NUM_TAGS 191 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -235,6 +235,7 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_loaderror_type); INSERT_TAG(jl_initerror_type); INSERT_TAG(jl_undefvarerror_type); + INSERT_TAG(jl_fielderror_type); INSERT_TAG(jl_stackovf_exception); INSERT_TAG(jl_diverror_exception); INSERT_TAG(jl_interrupt_exception); From 26752324dda65685f1acd046563c07f75e0a5635 Mon Sep 17 00:00:00 2001 From: Arhik Date: Wed, 22 May 2024 15:29:34 +0530 Subject: [PATCH 06/19] increment tag count From a0bb804a56e76851608bcf923d4124f5bad03fb5 Mon Sep 17 00:00:00 2001 From: Arhik Date: Thu, 23 May 2024 00:38:59 +0530 Subject: [PATCH 07/19] fixing existing tests --- base/reflection.jl | 2 +- src/jltypes.c | 2 +- stdlib/LinearAlgebra/test/bunchkaufman.jl | 2 +- stdlib/LinearAlgebra/test/cholesky.jl | 2 +- stdlib/LinearAlgebra/test/eigen.jl | 4 ++-- stdlib/LinearAlgebra/test/hessenberg.jl | 2 +- stdlib/LinearAlgebra/test/lq.jl | 2 +- stdlib/LinearAlgebra/test/lu.jl | 4 ++-- stdlib/LinearAlgebra/test/qr.jl | 8 ++++---- stdlib/LinearAlgebra/test/schur.jl | 6 +++--- stdlib/LinearAlgebra/test/svd.jl | 10 +++++----- test/compiler/codegen.jl | 2 +- test/compiler/inference.jl | 2 +- test/core.jl | 6 +++--- test/namedtuple.jl | 14 +++++++------- test/syntax.jl | 2 +- 16 files changed, 35 insertions(+), 35 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 3fead12f2eb8e..4417091acd7a7 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -976,7 +976,7 @@ julia> struct Foo end julia> Base.fieldindex(Foo, :z) -ERROR: type Foo has no field z +ERROR: FieldError: type Foo has no field z Stacktrace: [...] diff --git a/src/jltypes.c b/src/jltypes.c index 37852dcb0004c..fb65a9fca5d7e 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3727,7 +3727,7 @@ void post_boot_hooks(void) jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError")); jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError")); jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError"); - jl_fielderror_type = (jl_datatype_t*)core("FieldError"); + jl_fielderror_type = (jl_datatype_t*)core("FieldError"); jl_atomicerror_type = (jl_datatype_t*)core("ConcurrencyViolationError"); jl_interrupt_exception = jl_new_struct_uninit((jl_datatype_t*)core("InterruptException")); jl_boundserror_type = (jl_datatype_t*)core("BoundsError"); diff --git a/stdlib/LinearAlgebra/test/bunchkaufman.jl b/stdlib/LinearAlgebra/test/bunchkaufman.jl index d2305844db63e..68c519d1197ed 100644 --- a/stdlib/LinearAlgebra/test/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/test/bunchkaufman.jl @@ -114,7 +114,7 @@ bimint = rand(1:5, n, 2) bc1 = bunchkaufman(Symmetric(asym, uplo)) @test getproperty(bc1, uplo)*bc1.D*transpose(getproperty(bc1, uplo)) ≈ asym[bc1.p, bc1.p] @test getproperty(bc1, uplo)*bc1.D*transpose(getproperty(bc1, uplo)) ≈ bc1.P*asym*transpose(bc1.P) - @test_throws ErrorException bc1.Z + @test_throws FieldError bc1.Z @test_throws ArgumentError uplo === :L ? bc1.U : bc1.L end # test Base.iterate diff --git a/stdlib/LinearAlgebra/test/cholesky.jl b/stdlib/LinearAlgebra/test/cholesky.jl index 45b3c2445a187..f6910a19632a9 100644 --- a/stdlib/LinearAlgebra/test/cholesky.jl +++ b/stdlib/LinearAlgebra/test/cholesky.jl @@ -17,7 +17,7 @@ function unary_ops_tests(a, ca, tol; n=size(a, 1)) @test logabsdet_ca[1] ≈ logabsdet_a[1] @test logabsdet_ca[2] ≈ logabsdet_a[2] @test isposdef(ca) - @test_throws ErrorException ca.Z + @test_throws FieldError ca.Z @test size(ca) == size(a) @test Array(copy(ca)) ≈ a @test tr(ca) ≈ tr(a) skip=ca isa CholeskyPivoted diff --git a/stdlib/LinearAlgebra/test/eigen.jl b/stdlib/LinearAlgebra/test/eigen.jl index 174deffbc53e9..a82c745436009 100644 --- a/stdlib/LinearAlgebra/test/eigen.jl +++ b/stdlib/LinearAlgebra/test/eigen.jl @@ -80,7 +80,7 @@ aimg = randn(n,n)/2 @test eigvecs(asym_sg, ASG2) == f.vectors @test eigvals(f) === f.values @test eigvecs(f) === f.vectors - @test_throws ErrorException f.Z + @test_throws FieldError f.Z d,v = eigen(asym_sg, ASG2) @test d == f.values @@ -141,7 +141,7 @@ aimg = randn(n,n)/2 @test f.values ≈ eigvals(a1_nsg, a2_nsg; sortby = sortfunc) @test prod(f.values) ≈ prod(eigvals(a1_nsg/a2_nsg, sortby = sortfunc)) atol=50000ε @test eigvecs(a1_nsg, a2_nsg; sortby = sortfunc) == f.vectors - @test_throws ErrorException f.Z + @test_throws FieldError f.Z g = eigen(a1_nsg, Diagonal(1:n1)) @test a1_nsg*g.vectors ≈ (Diagonal(1:n1)*g.vectors) * Diagonal(g.values) diff --git a/stdlib/LinearAlgebra/test/hessenberg.jl b/stdlib/LinearAlgebra/test/hessenberg.jl index 90846ffc1defd..767f40aa1e53f 100644 --- a/stdlib/LinearAlgebra/test/hessenberg.jl +++ b/stdlib/LinearAlgebra/test/hessenberg.jl @@ -148,7 +148,7 @@ let n = 10 @test size(H.Q, 2) == size(A, 2) @test size(H.Q) == size(A) @test size(H) == size(A) - @test_throws ErrorException H.Z + @test_throws FieldError H.Z @test convert(Array, H) ≈ A @test (H.Q * H.H) * H.Q' ≈ A ≈ (Matrix(H.Q) * Matrix(H.H)) * Matrix(H.Q)' @test (H.Q' * A) * H.Q ≈ H.H diff --git a/stdlib/LinearAlgebra/test/lq.jl b/stdlib/LinearAlgebra/test/lq.jl index 44f920db25557..c3499f7f46fa6 100644 --- a/stdlib/LinearAlgebra/test/lq.jl +++ b/stdlib/LinearAlgebra/test/lq.jl @@ -50,7 +50,7 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) for (ii, lq_obj) in enumerate(lqa) @test ref_obs[ii] == lq_obj end - @test_throws ErrorException lqa.Z + @test_throws FieldError lqa.Z @test Array(copy(adjoint(lqa))) ≈ a' @test q*squareQ(q)' ≈ Matrix(I, n, n) @test l*q ≈ a diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index 0cb45047a118c..56a402d70493e 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -59,7 +59,7 @@ dimg = randn(n)/2 κ = cond(a,1) @testset "(Automatic) Square LU decomposition" begin lua = factorize(a) - @test_throws ErrorException lua.Z + @test_throws FieldError lua.Z l,u,p = lua.L, lua.U, lua.p ll,ul,pl = @inferred lu(a) @test ll * ul ≈ a[pl,:] @@ -88,7 +88,7 @@ dimg = randn(n)/2 lud = @inferred lu(d) @test LinearAlgebra.issuccess(lud) @test @inferred(lu(lud)) == lud - @test_throws ErrorException lud.Z + @test_throws FieldError lud.Z @test lud.L*lud.U ≈ lud.P*Array(d) @test lud.L*lud.U ≈ Array(d)[lud.p,:] @test AbstractArray(lud) ≈ d diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index aef2e23740487..b6e9ce3a82743 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -50,7 +50,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) @testset "QR decomposition (without pivoting)" begin qra = @inferred qr(a) q, r = qra.Q, qra.R - @test_throws ErrorException qra.Z + @test_throws FieldError qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q*squareQ(q)' ≈ Matrix(I, a_1, a_1) @test q'*Matrix(1.0I, a_1, a_1)' ≈ squareQ(q)' @@ -79,7 +79,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) @testset "Thin QR decomposition (without pivoting)" begin qra = @inferred qr(a[:, 1:n1], NoPivot()) q,r = qra.Q, qra.R - @test_throws ErrorException qra.Z + @test_throws FieldError qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q'*rectangularQ(q) ≈ Matrix(I, a_1, n1) @test q*r ≈ a[:, 1:n1] @@ -106,7 +106,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) qrpa = factorize(a[1:n1,:]) q,r = qrpa.Q, qrpa.R - @test_throws ErrorException qrpa.Z + @test_throws FieldError qrpa.Z p = qrpa.p @test q'*squareQ(q) ≈ Matrix(I, n1, n1) @test q*squareQ(q)' ≈ Matrix(I, n1, n1) @@ -134,7 +134,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) @testset "(Automatic) Thin (pivoted) QR decomposition" begin qrpa = factorize(a[:,1:n1]) q,r = qrpa.Q, qrpa.R - @test_throws ErrorException qrpa.Z + @test_throws FieldError qrpa.Z p = qrpa.p @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q*squareQ(q)' ≈ Matrix(I, a_1, a_1) diff --git a/stdlib/LinearAlgebra/test/schur.jl b/stdlib/LinearAlgebra/test/schur.jl index c9a5d92dbdae8..f3d494fba7942 100644 --- a/stdlib/LinearAlgebra/test/schur.jl +++ b/stdlib/LinearAlgebra/test/schur.jl @@ -33,7 +33,7 @@ aimg = randn(n,n)/2 @test sort(imag(f.values)) ≈ sort(imag(d)) @test istriu(f.Schur) || eltype(a)<:Real @test convert(Array, f) ≈ a - @test_throws ErrorException f.A + @test_throws FieldError f.A sch, vecs, vals = schur(UpperTriangular(triu(a))) @test vecs*sch*vecs' ≈ triu(a) @@ -68,7 +68,7 @@ aimg = randn(n,n)/2 O = ordschur(S, select) sum(select) != 0 && @test S.values[findall(select)] ≈ O.values[1:sum(select)] @test O.vectors*O.Schur*O.vectors' ≈ ordschura - @test_throws ErrorException f.A + @test_throws FieldError f.A Snew = LinearAlgebra.Schur(S.T, S.Z, S.values) SchurNew = ordschur!(copy(Snew), select) @test O.vectors ≈ SchurNew.vectors @@ -88,7 +88,7 @@ aimg = randn(n,n)/2 @test f.Q*f.T*f.Z' ≈ a2_sf @test istriu(f.S) || eltype(a)<:Real @test istriu(f.T) || eltype(a)<:Real - @test_throws ErrorException f.A + @test_throws FieldError f.A sstring = sprint((t, s) -> show(t, "text/plain", s), f.S) tstring = sprint((t, s) -> show(t, "text/plain", s), f.T) diff --git a/stdlib/LinearAlgebra/test/svd.jl b/stdlib/LinearAlgebra/test/svd.jl index 8f462dee94d06..9e8b5d5cda7d2 100644 --- a/stdlib/LinearAlgebra/test/svd.jl +++ b/stdlib/LinearAlgebra/test/svd.jl @@ -75,7 +75,7 @@ aimg = randn(n,n)/2 @test usv.U * (Diagonal(usv.S) * usv.Vt) ≈ a @test convert(Array, usv) ≈ a @test usv.Vt' ≈ usv.V - @test_throws ErrorException usv.Z + @test_throws FieldError usv.Z b = rand(eltya,n) @test usv\b ≈ a\b @test Base.propertynames(usv) == (:U, :S, :V, :Vt) @@ -94,7 +94,7 @@ aimg = randn(n,n)/2 @test usv.U * (Diagonal(usv.S) * usv.Vt) ≈ transform(a) @test convert(Array, usv) ≈ transform(a) @test usv.Vt' ≈ usv.V - @test_throws ErrorException usv.Z + @test_throws FieldError usv.Z b = rand(eltya,n) @test usv\b ≈ transform(a)\b end @@ -106,8 +106,8 @@ aimg = randn(n,n)/2 @test gsvd.U*gsvd.D1*gsvd.R*gsvd.Q' ≈ a @test gsvd.V*gsvd.D2*gsvd.R*gsvd.Q' ≈ a_svd @test usv.Vt' ≈ usv.V - @test_throws ErrorException usv.Z - @test_throws ErrorException gsvd.Z + @test_throws FieldError usv.Z + @test_throws FieldError gsvd.Z @test gsvd.vals ≈ svdvals(a,a_svd) α = eltya == Int ? -1 : rand(eltya) β = svd(α) @@ -148,7 +148,7 @@ aimg = randn(n,n)/2 @test usv.U * (Diagonal(usv.S) * usv.Vt) ≈ T(asym) @test convert(Array, usv) ≈ T(asym) @test usv.Vt' ≈ usv.V - @test_throws ErrorException usv.Z + @test_throws FieldError usv.Z b = rand(eltya,n) @test usv\b ≈ T(asym)\b end diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index f9b8b1c5fb74d..529ee7b611448 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -859,7 +859,7 @@ foo50964(1) # Shouldn't assert! # https://github.com/JuliaLang/julia/issues/51233 obj51233 = (1,) -@test_throws ErrorException obj51233.x +@test_throws FieldError obj51233.x # Very specific test for multiversioning if Sys.ARCH === :x86_64 diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 7d6e42a4b5731..6fe050bbd5935 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -479,7 +479,7 @@ end @test f15259(1,2) == (1,2,1,2) # check that error cases are still correct @eval g15259(x,y) = (a = $(Expr(:new, :A15259, :x, :y)); a.z) -@test_throws ErrorException g15259(1,1) +@test_throws FieldError g15259(1,1) @eval h15259(x,y) = (a = $(Expr(:new, :A15259, :x, :y)); getfield(a, 3)) @test_throws BoundsError h15259(1,1) diff --git a/test/core.jl b/test/core.jl index 5a65b8a92c3fd..8d8db28eac062 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1924,9 +1924,9 @@ end # issue #4526 f4526(x) = isa(x.a, Nothing) -@test_throws ErrorException f4526(1) -@test_throws ErrorException f4526(im) -@test_throws ErrorException f4526(1+2im) +@test_throws FieldError f4526(1) +@test_throws FieldError f4526(im) +@test_throws FieldError f4526(1+2im) # issue #4528 function f4528(A, B) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 48aa8ea4a2591..2c9c1ef3cff53 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -28,13 +28,13 @@ @test (x=4, y=5, z=6)[()] == NamedTuple() @test (x=4, y=5, z=6)[:] == (x=4, y=5, z=6) @test NamedTuple()[()] == NamedTuple() -@test_throws ErrorException (x=4, y=5, z=6).a +@test_throws FieldError (x=4, y=5, z=6).a @test_throws BoundsError (a=2,)[0] @test_throws BoundsError (a=2,)[2] -@test_throws ErrorException (x=4, y=5, z=6)[(:a,)] -@test_throws ErrorException (x=4, y=5, z=6)[(:x, :a)] -@test_throws ErrorException (x=4, y=5, z=6)[[:a]] -@test_throws ErrorException (x=4, y=5, z=6)[[:x, :a]] +@test_throws FieldError (x=4, y=5, z=6)[(:a,)] +@test_throws FieldError (x=4, y=5, z=6)[(:x, :a)] +@test_throws FieldError (x=4, y=5, z=6)[[:a]] +@test_throws FieldError (x=4, y=5, z=6)[[:x, :a]] @test_throws ErrorException (x=4, y=5, z=6)[(:x, :x)] @test length(NamedTuple()) == 0 @@ -255,7 +255,7 @@ function abstr_nt_22194_2() a = NamedTuple[(a=1,), (b=2,)] return a[1].b end -@test_throws ErrorException abstr_nt_22194_2() +@test_throws FieldError abstr_nt_22194_2() @test Base.return_types(abstr_nt_22194_2, ()) == Any[Any] mutable struct HasAbstractNamedTuples @@ -442,7 +442,7 @@ end for NT in (NamedTuple{(:a, :b), Union{}}, NamedTuple{(:a, :b), T} where T<:Union{}) @test fieldtype(NT, 1) == Union{} @test fieldtype(NT, :b) == Union{} - @test_throws ErrorException fieldtype(NT, :c) + @test_throws FieldError fieldtype(NT, :c) @test_throws BoundsError fieldtype(NT, 0) @test_throws BoundsError fieldtype(NT, 3) @test Base.return_types((Type{NT},)) do NT; fieldtype(NT, :a); end == Any[Type{Union{}}] diff --git a/test/syntax.jl b/test/syntax.jl index 0a2cc491463ad..c56a2fb2219d7 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2831,7 +2831,7 @@ end @test a == 5 @test b == 6 - @test_throws ErrorException (; a, b) = (x=1,) + @test_throws FieldError (; a, b) = (x=1,) @test Meta.isexpr(Meta.@lower(begin (a, b; c) = x end), :error) @test Meta.isexpr(Meta.@lower(begin (a, b; c) = x, y end), :error) From 7f9fc8f14ae6d9a2201b9953c8d6e54088688d8e Mon Sep 17 00:00:00 2001 From: Arhik Date: Thu, 23 May 2024 07:22:56 +0530 Subject: [PATCH 08/19] missed few test fixes and formatting --- base/errorshow.jl | 2 +- test/syntax.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 29e0c6e53cf0a..57123b346c715 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -369,7 +369,7 @@ end function showerror(io::IO, exc::FieldError) @nospecialize - println(io, "FieldError: type $(exc.type) has no field $(exc.field)") + print(io, "FieldError: type $(exc.type) has no field $(exc.field)") Base.Experimental.show_error_hints(io, exc) end diff --git a/test/syntax.jl b/test/syntax.jl index c56a2fb2219d7..f2dc464d4cca4 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2840,7 +2840,7 @@ end f((; a, b)) = a, b @test f((b=3, a=4)) == (4, 3) @test f((b=3, c=2, a=4)) == (4, 3) - @test_throws ErrorException f((;)) + @test_throws FieldError f((;)) # with type annotation let num, den, a, b From a879a18030f661fc8ad10d013a9c3c89602be741 Mon Sep 17 00:00:00 2001 From: Arhik Date: Thu, 23 May 2024 16:05:48 +0530 Subject: [PATCH 09/19] Test for Dict error hint and FieldError in general --- test/errorshow.jl | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/errorshow.jl b/test/errorshow.jl index 5d0640601b398..7afa3a080c02c 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -808,6 +808,62 @@ end @test_throws ArgumentError("invalid index: \"foo\" of type String") [1]["foo"] @test_throws ArgumentError("invalid index: nothing of type Nothing") [1][nothing] +# issue #53618 +@testset "FieldErrorHint" begin + struct FieldFoo + a::Float32 + b::Int64 + end + + s = FieldFoo(1, 2) + + @test s.a == 1.0f0 + @test s.b == 2 + @test_throws FieldError s.c + + ex = try + s.c + catch e + e + end::FieldError + + # Check error message first + errorMsg = sprint(Base.showerror, ex) + @test occursin("FieldError: type FieldFoo has no field c", errorMsg) + + d = Dict(s => 1) + + for fld in fieldnames(Dict) + ex = try + getfield(d, fld) + catch e + print(e) + end + @test !(ex isa Type) || ex <: FieldError + end + @test_throws FieldError d.a + + ex = try + d.c + catch e + e + end::FieldError + + errorMsg = sprint(Base.showerror, ex) + @test occursin("FieldError: type Dict has no field c", errorMsg) + # Check hint message + hintExpected = """ + Did you mean to access dict values using key: `c` ? + Consider using `indexing` operation. + Example: + ```julia + dict = Dict(c=>someValue) + dict[c] + ``` + """ + @test occursin(hintExpected, errorMsg) +end + # test showing MethodError with type argument struct NoMethodsDefinedHere; end let buf = IOBuffer() From cb1d5c8516cf3e98301845503efa74095e15f366 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 24 May 2024 07:01:08 +0530 Subject: [PATCH 10/19] register hint handlers for test We will have to register handlers for tests separately again. --- test/errorshow.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/errorshow.jl b/test/errorshow.jl index 7afa3a080c02c..048ec47b4faf4 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -10,7 +10,7 @@ Base.Experimental.register_error_hint(Base.noncallable_number_hint_handler, Meth Base.Experimental.register_error_hint(Base.string_concatenation_hint_handler, MethodError) Base.Experimental.register_error_hint(Base.methods_on_iterable, MethodError) Base.Experimental.register_error_hint(Base.nonsetable_type_hint_handler, MethodError) - +Base.Experimental.register_error_hint(Base.fielderror_hint_handler, FieldError) @testset "SystemError" begin err = try; systemerror("reason", Cint(0)); false; catch ex; ex; end::SystemError From fb1e0f7929cb5ef8c501f770b47d4b601d44dd64 Mon Sep 17 00:00:00 2001 From: Arhik Date: Mon, 27 May 2024 18:31:50 +0530 Subject: [PATCH 11/19] codegen changes for fielderror --- base/errorshow.jl | 4 ++-- src/codegen.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 57123b346c715..b7cde32cf428d 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -369,7 +369,7 @@ end function showerror(io::IO, exc::FieldError) @nospecialize - print(io, "FieldError: type $(exc.type) has no field $(exc.field)") + print(io, "FieldError: type $(exc.type |> nameof) has no field $(exc.field)") Base.Experimental.show_error_hints(io, exc) end @@ -1097,7 +1097,7 @@ function fielderror_hint_handler(io, exc) @nospecialize field = exc.field type = exc.type - if type == :Dict + if type <: Dict println(io, """ \nDid you mean to access dict values using key: `$field` ? diff --git a/src/codegen.cpp b/src/codegen.cpp index 51d383e9a61e7..82ea1852ecb11 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4080,7 +4080,7 @@ static jl_llvm_functions_t jl_value_t *rettype, jl_codegen_params_t ¶ms); -static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *type, jl_cgval_t name); +static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatype_t *type, jl_cgval_t name); static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, jl_value_t *rt, @@ -4590,7 +4590,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, assert(jl_svec_len(fn) == 1); Value *typ_sym = literal_pointer_val(ctx, jl_svecref(fn, 0)); Value *cond = ctx.builder.CreateICmpEQ(mark_callee_rooted(ctx, typ_sym), mark_callee_rooted(ctx, boxed(ctx, fld))); - emit_hasnofield_error_ifnot(ctx, cond, utt->name->name, fld); + emit_hasnofield_error_ifnot(ctx, cond, utt, fld); *ret = emit_getfield_knownidx(ctx, obj, 0, utt, order); return true; } @@ -4598,7 +4598,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, Value *index = ctx.builder.CreateCall(prepare_call(jlfieldindex_func), {emit_typeof(ctx, obj, false, false), boxed(ctx, fld), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)}); Value *cond = ctx.builder.CreateICmpNE(index, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), -1)); - emit_hasnofield_error_ifnot(ctx, cond, utt->name->name, fld); + emit_hasnofield_error_ifnot(ctx, cond, utt, fld); Value *idx2 = ctx.builder.CreateAdd(ctx.builder.CreateIntCast(index, ctx.types().T_size, false), ConstantInt::get(ctx.types().T_size, 1)); // getfield_unknown is 1 based if (emit_getfield_unknownidx(ctx, ret, obj, idx2, utt, jl_false, order)) return true; @@ -5429,7 +5429,7 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bo // --- accessing and assigning variables --- -static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *type, jl_cgval_t name) +static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatype_t *type, jl_cgval_t name) { ++EmittedUndefVarErrors; assert(name.typ == (jl_value_t*)jl_symbol_type); From 752ac7cc9a17bad45baca0b86701cdb426135a83 Mon Sep 17 00:00:00 2001 From: Arhik Date: Fri, 7 Jun 2024 19:11:32 +0530 Subject: [PATCH 12/19] typo in comment typo --- base/errorshow.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index b7cde32cf428d..8e3452a7d7b01 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1092,7 +1092,7 @@ end Experimental.register_error_hint(methods_on_iterable, MethodError) -# Display a hint in case the use tries to access non-member fields of container type datastructures +# Display a hint in case the user tries to access non-member fields of container type datastructures function fielderror_hint_handler(io, exc) @nospecialize field = exc.field From 5dfe5f879796000eb8f89da434c667a199646e39 Mon Sep 17 00:00:00 2001 From: Arhik Date: Sat, 8 Jun 2024 23:53:42 +0530 Subject: [PATCH 13/19] symbol instead of value in field error hint Co-authored-by: Lilith Orion Hafner --- base/errorshow.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 8e3452a7d7b01..41bc6b8194227 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1104,7 +1104,7 @@ function fielderror_hint_handler(io, exc) Consider using `indexing` operation. Example: ```julia - dict = Dict($(field)=>someValue) + dict = Dict(:$(field)=>someValue) dict[$(field)] ``` """ From 90066355f9beb2a6f489652e8e28cfd7de6ed3f2 Mon Sep 17 00:00:00 2001 From: Arhik Date: Sun, 9 Jun 2024 14:43:08 +0530 Subject: [PATCH 14/19] removing code block --- base/errorshow.jl | 14 ++++++++------ test/errorshow.jl | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 41bc6b8194227..b1e79e522d69b 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1100,13 +1100,15 @@ function fielderror_hint_handler(io, exc) if type <: Dict println(io, """ - \nDid you mean to access dict values using key: `$field` ? + \nDid you mean to access dict values using key: `:$field` ? Consider using `indexing` operation. - Example: - ```julia - dict = Dict(:$(field)=>someValue) - dict[$(field)] - ``` + + # Example + julia> dict = Dict(:$(field)=>5) + Dict{Symbol, Int64} with 1 entry: + :$(field) => 5 + julia> dict[:$(field)] + 5 """ ) end diff --git a/test/errorshow.jl b/test/errorshow.jl index 048ec47b4faf4..ee0187afcae0c 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -853,13 +853,15 @@ end @test occursin("FieldError: type Dict has no field c", errorMsg) # Check hint message hintExpected = """ - Did you mean to access dict values using key: `c` ? + Did you mean to access dict values using key: `:c` ? Consider using `indexing` operation. - Example: - ```julia - dict = Dict(c=>someValue) - dict[c] - ``` + + # Example + julia> dict = Dict(:c=>5) + Dict{Symbol, Int64} with 1 entry: + :c => 5 + julia> dict[:c] + 5 """ @test occursin(hintExpected, errorMsg) end From a8ca205d03705927f97dce8472fd5a25cb308aeb Mon Sep 17 00:00:00 2001 From: Arhik Date: Sun, 9 Jun 2024 22:51:10 +0530 Subject: [PATCH 15/19] Apply suggestions from code review minor tweaks from suggestions Co-authored-by: Lilith Orion Hafner --- base/errorshow.jl | 3 ++- test/errorshow.jl | 20 ++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index b1e79e522d69b..c2ad7b8ebc5f6 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1101,11 +1101,12 @@ function fielderror_hint_handler(io, exc) println(io, """ \nDid you mean to access dict values using key: `:$field` ? - Consider using `indexing` operation. + Consider using indexing syntax. # Example julia> dict = Dict(:$(field)=>5) Dict{Symbol, Int64} with 1 entry: + :$(field) => 5 julia> dict[:$(field)] 5 diff --git a/test/errorshow.jl b/test/errorshow.jl index ee0187afcae0c..c0cb53cdfdb32 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -817,15 +817,11 @@ end s = FieldFoo(1, 2) - @test s.a == 1.0f0 - @test s.b == 2 - @test_throws FieldError s.c + @test s.a === 1.0f0 + @test s.b === 2 + test = @test_throws FieldError s.c - ex = try - s.c - catch e - e - end::FieldError + ex = test.value::FieldError # Check error message first errorMsg = sprint(Base.showerror, ex) @@ -841,13 +837,9 @@ end end @test !(ex isa Type) || ex <: FieldError end - @test_throws FieldError d.a + test = @test_throws FieldError d.c - ex = try - d.c - catch e - e - end::FieldError + ex = test.value::FieldError errorMsg = sprint(Base.showerror, ex) @test occursin("FieldError: type Dict has no field c", errorMsg) From 2063b9b9a2e0f24a56d3d38271afa6be221b6035 Mon Sep 17 00:00:00 2001 From: Arhik Date: Mon, 10 Jun 2024 00:19:37 +0530 Subject: [PATCH 16/19] suggestions fix --- base/errorshow.jl | 2 +- test/errorshow.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index c2ad7b8ebc5f6..a5af835a4c930 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1106,8 +1106,8 @@ function fielderror_hint_handler(io, exc) # Example julia> dict = Dict(:$(field)=>5) Dict{Symbol, Int64} with 1 entry: - :$(field) => 5 + julia> dict[:$(field)] 5 """ diff --git a/test/errorshow.jl b/test/errorshow.jl index c0cb53cdfdb32..caa53f1400c53 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -846,12 +846,13 @@ end # Check hint message hintExpected = """ Did you mean to access dict values using key: `:c` ? - Consider using `indexing` operation. + Consider using indexing syntax. # Example julia> dict = Dict(:c=>5) Dict{Symbol, Int64} with 1 entry: :c => 5 + julia> dict[:c] 5 """ From 7f09293ca27a2ac96fc27e70780a36db2f50a531 Mon Sep 17 00:00:00 2001 From: Arhik Date: Mon, 10 Jun 2024 09:02:03 +0530 Subject: [PATCH 17/19] 32 bit systems update --- test/errorshow.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/errorshow.jl b/test/errorshow.jl index caa53f1400c53..32f79f4c9c80d 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -812,13 +812,11 @@ end @testset "FieldErrorHint" begin struct FieldFoo a::Float32 - b::Int64 + b::Int end s = FieldFoo(1, 2) - @test s.a === 1.0f0 - @test s.b === 2 test = @test_throws FieldError s.c ex = test.value::FieldError From b1ef85ffaf5b46605e6e042636290c239fbbb519 Mon Sep 17 00:00:00 2001 From: Arhik Date: Mon, 10 Jun 2024 20:24:38 +0530 Subject: [PATCH 18/19] shorter description for error hint --- base/errorshow.jl | 19 ++++--------------- test/errorshow.jl | 13 +------------ 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index a5af835a4c930..702fee274cbe1 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1097,21 +1097,10 @@ function fielderror_hint_handler(io, exc) @nospecialize field = exc.field type = exc.type - if type <: Dict - println(io, - """ - \nDid you mean to access dict values using key: `:$field` ? - Consider using indexing syntax. - - # Example - julia> dict = Dict(:$(field)=>5) - Dict{Symbol, Int64} with 1 entry: - :$(field) => 5 - - julia> dict[:$(field)] - 5 - """ - ) + if type <: AbstractDict + print(io, "\nDid you mean to access dict values using key: `:$field` ? Consider using indexing syntax ") + printstyled(io, "dict[:$(field)]", color=:cyan) + println(io, "") end end diff --git a/test/errorshow.jl b/test/errorshow.jl index 32f79f4c9c80d..80352ddeaa9cf 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -842,18 +842,7 @@ end errorMsg = sprint(Base.showerror, ex) @test occursin("FieldError: type Dict has no field c", errorMsg) # Check hint message - hintExpected = """ - Did you mean to access dict values using key: `:c` ? - Consider using indexing syntax. - - # Example - julia> dict = Dict(:c=>5) - Dict{Symbol, Int64} with 1 entry: - :c => 5 - - julia> dict[:c] - 5 - """ + hintExpected = "Did you mean to access dict values using key: `:c` ? Consider using indexing syntax dict[:c]\n" @test occursin(hintExpected, errorMsg) end From 4f967182621a5031d5f29d015503f4ed3d2847a0 Mon Sep 17 00:00:00 2001 From: Arhik Date: Tue, 11 Jun 2024 20:26:55 +0530 Subject: [PATCH 19/19] Update base/errorshow.jl Co-authored-by: Lilith Orion Hafner --- base/errorshow.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 702fee274cbe1..cf1518a3cb533 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1100,7 +1100,7 @@ function fielderror_hint_handler(io, exc) if type <: AbstractDict print(io, "\nDid you mean to access dict values using key: `:$field` ? Consider using indexing syntax ") printstyled(io, "dict[:$(field)]", color=:cyan) - println(io, "") + println(io) end end