diff --git a/NEWS.md b/NEWS.md index 976c88ee65cb8..91b47d832eb29 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,7 +10,7 @@ Language changes Compiler/Runtime improvements ----------------------------- - +* The `@pure` macro is now deprecated. Use `Base.@assume_effects :foldable` instead ([#48682]). Command-line option changes --------------------------- diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 9a4859682cf31..0d0280e40e817 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -96,15 +96,11 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), all_effects = EFFECTS_TOTAL if !matches.nonoverlayed # currently we don't have a good way to execute the overlayed method definition, - # so we should give up pure/concrete eval when any of the matched methods is overlayed + # so we should give up concrete eval when any of the matched methods is overlayed f = nothing all_effects = Effects(all_effects; nonoverlayed=false) end - # try pure-evaluation - val = pure_eval_call(interp, f, applicable, arginfo) - val !== nothing && return CallMeta(val, all_effects, MethodResultPure(info)) # TODO: add some sort of edge(s) - 𝕃ₚ = ipo_lattice(interp) for i in 1:napplicable match = applicable[i]::MethodMatch @@ -788,40 +784,6 @@ struct MethodCallResult end end -function pure_eval_eligible(interp::AbstractInterpreter, - @nospecialize(f), applicable::Vector{Any}, arginfo::ArgInfo) - # XXX we need to check that this pure function doesn't call any overlayed method - return f !== nothing && - length(applicable) == 1 && - is_method_pure(applicable[1]::MethodMatch) && - is_all_const_arg(arginfo, #=start=#2) -end - -function is_method_pure(method::Method, @nospecialize(sig), sparams::SimpleVector) - if isdefined(method, :generator) - method.generator.expand_early || return false - mi = specialize_method(method, sig, sparams) - isa(mi, MethodInstance) || return false - staged = get_staged(mi) - (staged isa CodeInfo && (staged::CodeInfo).pure) || return false - return true - end - return method.pure -end -is_method_pure(match::MethodMatch) = is_method_pure(match.method, match.spec_types, match.sparams) - -function pure_eval_call(interp::AbstractInterpreter, - @nospecialize(f), applicable::Vector{Any}, arginfo::ArgInfo) - pure_eval_eligible(interp, f, applicable, arginfo) || return nothing - args = collect_const_args(arginfo, #=start=#2) - value = try - Core._apply_pure(f, args) - catch - return nothing - end - return Const(value) -end - # - true: eligible for concrete evaluation # - false: eligible for semi-concrete evaluation # - nothing: not eligible for either of it diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl index 729e9a9a49b94..8bc173add6eaa 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -791,6 +791,7 @@ function compute_frameinfo(ir::IRCode, call_resolved::Bool) check_effect_free!(ir, idx, stmt, inst[:type], 𝕃ₒ) end if callinfo !== nothing && isexpr(stmt, :call) + # TODO: pass effects here callinfo[idx] = resolve_call(ir, stmt, inst[:info]) elseif isexpr(stmt, :enter) @assert idx ≤ nstmts "try/catch inside new_nodes unsupported" diff --git a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl index d87b0edaf295e..26b0e5b404641 100644 --- a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl +++ b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl @@ -14,6 +14,7 @@ struct EACallInfo end function resolve_call(ir::IRCode, stmt::Expr, @nospecialize(info::CallInfo)) + # TODO: if effect free, return true sig = call_sig(ir, stmt) if sig === nothing return missing diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 55ae33c87e96b..f7723a968da3e 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -1010,7 +1010,6 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) tree.linetable = LineInfoNode[LineInfoNode(method.module, method.name, method.file, method.line, Int32(0))] tree.inferred = true tree.ssaflags = UInt8[0] - tree.pure = true set_inlineable!(tree, true) tree.parent = mi tree.rettype = Core.Typeof(rettype_const) diff --git a/base/deprecated.jl b/base/deprecated.jl index 79ae852ff22b1..3e18cfcf918fb 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -362,3 +362,31 @@ end end # END 1.9 deprecations + +# BEGIN 1.10 deprecations + +""" + @pure ex + +`@pure` gives the compiler a hint for the definition of a pure function, +helping for type inference. + +!!! warning + This macro is intended for internal compiler use and may be subject to changes. + +!!! warning + In Julia 1.8 and higher, it is favorable to use [`@assume_effects`](@ref) instead of `@pure`. + This is because `@assume_effects` allows a finer grained control over Julia's purity + modeling and the effect system enables a wider range of optimizations. + +!!! note + In Julia 1.10 this is deprecated in favor of [`@assume_effects`](@ref). + Specifically, `@assume_effects :foldable` provides similar guarentees. +""" +macro pure(ex) + f, l = __source__.file, __source__.line + @warn "`Base.@pure ex` at $f:$l is deprecated, use `Base.@assume_effects :foldable ex` instead." + return esc(:(Base.@assume_effects :foldable $ex)) +end + +# END 1.10 deprecations diff --git a/base/essentials.jl b/base/essentials.jl index a0d00c942ecd5..fc79f88f5c0b8 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -198,10 +198,6 @@ function _is_internal(__module__) return false end -# can be used in place of `@pure` (supposed to be used for bootstrapping) -macro _pure_meta() - return _is_internal(__module__) && Expr(:meta, :pure) -end # can be used in place of `@assume_effects :total` (supposed to be used for bootstrapping) macro _total_meta() return _is_internal(__module__) && Expr(:meta, Expr(:purity, diff --git a/base/expr.jl b/base/expr.jl index 0e6d73c9722d1..46e89bf64da8a 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -339,23 +339,6 @@ macro noinline(x) return annotate_meta_def_or_block(x, :noinline) end -""" - @pure ex - -`@pure` gives the compiler a hint for the definition of a pure function, -helping for type inference. - -!!! warning - This macro is intended for internal compiler use and may be subject to changes. - -!!! warning - In Julia 1.8 and higher, it is favorable to use [`@assume_effects`](@ref) instead of `@pure`. - This is because `@assume_effects` allows a finer grained control over Julia's purity - modeling and the effect system enables a wider range of optimizations. -""" -macro pure(ex) - esc(isa(ex, Expr) ? pushmeta!(ex, :pure) : ex) -end """ @constprop setting [ex] @@ -703,16 +686,6 @@ the following other `setting`s: Effect names may be prefixed by `!` to indicate that the effect should be removed from an earlier meta effect. For example, `:total !:nothrow` indicates that while the call is generally total, it may however throw. - ---- -## Comparison to `@pure` - -`@assume_effects :foldable` is similar to [`@pure`](@ref) with the primary -distinction that the `:consistent`-cy requirement applies world-age wise rather -than globally as described above. However, in particular, a method annotated -`@pure` should always be at least `:foldable`. -Another advantage is that effects introduced by `@assume_effects` are propagated to -callers interprocedurally while a purity defined by `@pure` is not. """ macro assume_effects(args...) lastex = args[end] diff --git a/doc/src/base/base.md b/doc/src/base/base.md index 2159a9ad9a9fc..7e45e2176478d 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -293,7 +293,6 @@ Base.@label Base.@simd Base.@polly Base.@generated -Base.@pure Base.@assume_effects Base.@deprecate ``` diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index 9ada683b1ddb0..6984a68cc5508 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -581,7 +581,7 @@ A unique'd container describing the shared metadata for a single method. Pointers to non-AST things that have been interpolated into the AST, required by compression of the AST, type-inference, or the generation of native code. - * `nargs`, `isva`, `called`, `isstaged`, `pure` + * `nargs`, `isva`, `called`, `is_for_opaque_closure`, Descriptive bit-fields for the source code of this Method. @@ -759,11 +759,6 @@ Boolean properties: Whether this should propagate `@inbounds` when inlined for the purpose of eliding `@boundscheck` blocks. - * `pure` - - Whether this is known to be a pure function of its arguments, without respect to the - state of the method caches or other mutable global state. - `UInt8` settings: diff --git a/src/ast.c b/src/ast.c index 0ff7c882ab8e7..ca22fb463ce9c 100644 --- a/src/ast.c +++ b/src/ast.c @@ -66,7 +66,6 @@ JL_DLLEXPORT jl_sym_t *jl_boundscheck_sym; JL_DLLEXPORT jl_sym_t *jl_inbounds_sym; JL_DLLEXPORT jl_sym_t *jl_copyast_sym; JL_DLLEXPORT jl_sym_t *jl_cfunction_sym; -JL_DLLEXPORT jl_sym_t *jl_pure_sym; JL_DLLEXPORT jl_sym_t *jl_loopinfo_sym; JL_DLLEXPORT jl_sym_t *jl_meta_sym; JL_DLLEXPORT jl_sym_t *jl_inert_sym; @@ -328,7 +327,6 @@ void jl_init_common_symbols(void) jl_newvar_sym = jl_symbol("newvar"); jl_copyast_sym = jl_symbol("copyast"); jl_loopinfo_sym = jl_symbol("loopinfo"); - jl_pure_sym = jl_symbol("pure"); jl_meta_sym = jl_symbol("meta"); jl_list_sym = jl_symbol("list"); jl_unused_sym = jl_symbol("#unused#"); diff --git a/src/ircode.c b/src/ircode.c index 0e74f7700ebf2..20f826b4fcc7f 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -434,13 +434,12 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) } } -static jl_code_info_flags_t code_info_flags(uint8_t inferred, uint8_t propagate_inbounds, uint8_t pure, +static jl_code_info_flags_t code_info_flags(uint8_t inferred, uint8_t propagate_inbounds, uint8_t has_fcall, uint8_t inlining, uint8_t constprop) { jl_code_info_flags_t flags; flags.bits.inferred = inferred; flags.bits.propagate_inbounds = propagate_inbounds; - flags.bits.pure = pure; flags.bits.has_fcall = has_fcall; flags.bits.inlining = inlining; flags.bits.constprop = constprop; @@ -781,7 +780,7 @@ JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) 1 }; - jl_code_info_flags_t flags = code_info_flags(code->inferred, code->propagate_inbounds, code->pure, + jl_code_info_flags_t flags = code_info_flags(code->inferred, code->propagate_inbounds, code->has_fcall, code->inlining, code->constprop); write_uint8(s.s, flags.packed); write_uint8(s.s, code->purity.bits); @@ -880,7 +879,6 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->constprop = flags.bits.constprop; code->inferred = flags.bits.inferred; code->propagate_inbounds = flags.bits.propagate_inbounds; - code->pure = flags.bits.pure; code->has_fcall = flags.bits.has_fcall; code->purity.bits = read_uint8(s.s); code->inlining_cost = read_uint16(s.s); @@ -958,16 +956,6 @@ JL_DLLEXPORT uint8_t jl_ir_flag_inlining(jl_array_t *data) return flags.bits.inlining; } -JL_DLLEXPORT uint8_t jl_ir_flag_pure(jl_array_t *data) -{ - if (jl_is_code_info(data)) - return ((jl_code_info_t*)data)->pure; - assert(jl_typeis(data, jl_array_uint8_type)); - jl_code_info_flags_t flags; - flags.packed = ((uint8_t*)data->data)[0]; - return flags.bits.pure; -} - JL_DLLEXPORT uint8_t jl_ir_flag_has_fcall(jl_array_t *data) { if (jl_is_code_info(data)) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index c475184573faa..c5389978217d6 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -274,7 +274,6 @@ XX(jl_ios_fd) \ XX(jl_ios_get_nbyte_int) \ XX(jl_ir_flag_inferred) \ - XX(jl_ir_flag_pure) \ XX(jl_ir_flag_has_fcall) \ XX(jl_ir_flag_inlining) \ XX(jl_ir_inlining_cost) \ diff --git a/src/jltypes.c b/src/jltypes.c index d9f50d67d3f73..8d586a429d4a4 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2433,7 +2433,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_code_info_type = jl_new_datatype(jl_symbol("CodeInfo"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(22, + jl_perm_symsvec(21, "code", "codelocs", "ssavaluetypes", @@ -2450,13 +2450,12 @@ void jl_init_types(void) JL_GC_DISABLED "max_world", "inferred", "propagate_inbounds", - "pure", "has_fcall", "inlining", "constprop", "purity", "inlining_cost"), - jl_svec(22, + jl_svec(21, jl_array_any_type, jl_array_int32_type, jl_any_type, @@ -2474,7 +2473,6 @@ void jl_init_types(void) JL_GC_DISABLED jl_bool_type, jl_bool_type, jl_bool_type, - jl_bool_type, jl_uint8_type, jl_uint8_type, jl_uint8_type, @@ -2485,7 +2483,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_method_type = jl_new_datatype(jl_symbol("Method"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(29, + jl_perm_symsvec(28, "name", "module", "file", @@ -2511,11 +2509,10 @@ void jl_init_types(void) JL_GC_DISABLED "nospecialize", "nkw", "isva", - "pure", "is_for_opaque_closure", "constprop", "purity"), - jl_svec(29, + jl_svec(28, jl_symbol_type, jl_module_type, jl_symbol_type, @@ -2542,7 +2539,6 @@ void jl_init_types(void) JL_GC_DISABLED jl_int32_type, jl_bool_type, jl_bool_type, - jl_bool_type, jl_uint8_type, jl_uint8_type), jl_emptysvec, diff --git a/src/julia.h b/src/julia.h index 03efa773d026c..b84f3305dd021 100644 --- a/src/julia.h +++ b/src/julia.h @@ -284,7 +284,6 @@ typedef struct _jl_code_info_t { // various boolean properties: uint8_t inferred; uint8_t propagate_inbounds; - uint8_t pure; uint8_t has_fcall; // uint8 settings uint8_t inlining; // 0 = default; 1 = @inline; 2 = @noinline @@ -342,7 +341,6 @@ typedef struct _jl_method_t { // of another method. // various boolean properties uint8_t isva; - uint8_t pure; uint8_t is_for_opaque_closure; // uint8 settings uint8_t constprop; // 0x00 = use heuristic; 0x01 = aggressive; 0x02 = none @@ -1843,7 +1841,6 @@ JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code); JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t *metadata, jl_array_t *data); JL_DLLEXPORT uint8_t jl_ir_flag_inferred(jl_array_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_flag_inlining(jl_array_t *data) JL_NOTSAFEPOINT; -JL_DLLEXPORT uint8_t jl_ir_flag_pure(jl_array_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_flag_has_fcall(jl_array_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint16_t jl_ir_inlining_cost(jl_array_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT ssize_t jl_ir_nslots(jl_array_t *data) JL_NOTSAFEPOINT; diff --git a/src/julia_internal.h b/src/julia_internal.h index 21ac6dc4205ea..8751281a9d174 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -598,7 +598,6 @@ STATIC_INLINE jl_value_t *undefref_check(jl_datatype_t *dt, jl_value_t *v) JL_NO typedef struct { uint8_t inferred:1; uint8_t propagate_inbounds:1; - uint8_t pure:1; uint8_t has_fcall:1; uint8_t inlining:2; // 0 = use heuristic; 1 = aggressive; 2 = none uint8_t constprop:2; // 0 = use heuristic; 1 = aggressive; 2 = none @@ -1570,7 +1569,6 @@ extern JL_DLLEXPORT jl_sym_t *jl_boundscheck_sym; extern JL_DLLEXPORT jl_sym_t *jl_inbounds_sym; extern JL_DLLEXPORT jl_sym_t *jl_copyast_sym; extern JL_DLLEXPORT jl_sym_t *jl_cfunction_sym; -extern JL_DLLEXPORT jl_sym_t *jl_pure_sym; extern JL_DLLEXPORT jl_sym_t *jl_loopinfo_sym; extern JL_DLLEXPORT jl_sym_t *jl_meta_sym; extern JL_DLLEXPORT jl_sym_t *jl_inert_sym; diff --git a/src/method.c b/src/method.c index b1f4051e28a82..cce217230968c 100644 --- a/src/method.c +++ b/src/method.c @@ -312,9 +312,7 @@ static void jl_code_info_set_ir(jl_code_info_t *li, jl_expr_t *ir) jl_array_t *meta = ((jl_expr_t*)st)->args; for (k = 0; k < na; k++) { jl_value_t *ma = jl_array_ptr_ref(meta, k); - if (ma == (jl_value_t*)jl_pure_sym) - li->pure = 1; - else if (ma == (jl_value_t*)jl_inline_sym) + if (ma == (jl_value_t*)jl_inline_sym) li->inlining = 1; else if (ma == (jl_value_t*)jl_noinline_sym) li->inlining = 2; @@ -474,7 +472,6 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void) src->max_world = ~(size_t)0; src->inferred = 0; src->propagate_inbounds = 0; - src->pure = 0; src->has_fcall = 0; src->edges = jl_nothing; src->constprop = 0; @@ -678,7 +675,6 @@ static void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) } } m->called = called; - m->pure = src->pure; m->constprop = src->constprop; m->purity.bits = src->purity.bits; jl_add_function_name_to_lineinfo(src, (jl_value_t*)m->name); diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index a45523bc94d7d..b11df48daa08f 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -79,7 +79,7 @@ const TAGS = Any[ @assert length(TAGS) == 255 -const ser_version = 22 # do not make changes without bumping the version #! +const ser_version = 23 # do not make changes without bumping the version #! format_version(::AbstractSerializer) = ser_version format_version(s::Serializer) = s.version @@ -1060,7 +1060,6 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) if template !== nothing # TODO: compress template meth.source = template::CodeInfo - meth.pure = template.pure if !@isdefined(slot_syms) slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames) end @@ -1191,7 +1190,9 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo}) end end ci.propagate_inbounds = deserialize(s) - ci.pure = deserialize(s) + if format_version(s) < 23 + deserialize(s) # `pure` field has been removed + end if format_version(s) >= 20 ci.has_fcall = deserialize(s) end diff --git a/test/compiler/AbstractInterpreter.jl b/test/compiler/AbstractInterpreter.jl index ac1f34743e18e..57281fa3ad723 100644 --- a/test/compiler/AbstractInterpreter.jl +++ b/test/compiler/AbstractInterpreter.jl @@ -93,7 +93,7 @@ overlay_match(::Any) = nothing overlay_match(x) end |> only === Union{Nothing,Missing} -# partial pure/concrete evaluation +# partial concrete evaluation @test Base.return_types(; interp=MTOverlayInterp()) do isbitstype(Int) ? nothing : missing end |> only === Nothing @@ -110,7 +110,7 @@ end issue41694(3) == 6 ? nothing : missing end |> only === Nothing -# disable partial pure/concrete evaluation when tainted by any overlayed call +# disable partial concrete evaluation when tainted by any overlayed call Base.@assume_effects :total totalcall(f, args...) = f(args...) @test Base.return_types(; interp=MTOverlayInterp()) do if totalcall(strangesin, 1.0) == cos(1.0) diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index 79285f62b0947..ba13f175c674b 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -119,23 +119,11 @@ f() = 2 # Test that MiniCassette is at least somewhat capable by overdubbing gcd @test overdub(Ctx(), gcd, 10, 20) === gcd(10, 20) -# Test that pure propagates for Cassette -Base.@pure isbitstype(T) = Base.isbitstype(T) -f31012(T) = Val(isbitstype(T)) -@test @inferred(overdub(Ctx(), f31012, Int64)) == Val(true) - @generated bar(::Val{align}) where {align} = :(42) foo(i) = i+bar(Val(1)) @test @inferred(overdub(Ctx(), foo, 1)) == 43 -# Check that misbehaving pure functions propagate their error -Base.@pure func1() = 42 -Base.@pure func2() = (this_is_an_exception; func1()) -func3() = func2() -@test_throws UndefVarError func3() - - # overlay method tables # ===================== diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 09c687ecadf3b..48105f2bb8029 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -563,20 +563,6 @@ f18450() = ifelse(true, Tuple{Vararg{Int}}, Tuple{Vararg}) # issue #18569 @test !Core.Compiler.isconstType(Type{Tuple}) -# ensure pure attribute applies correctly to all signatures of fpure -Base.@pure function fpure(a=rand(); b=rand()) - # use the `rand` function since it is known to be `@inline` - # but would be too big to inline - return a + b + rand() -end - -@test which(fpure, ()).pure -@test which(fpure, (typeof(pi),)).pure - -# Make sure @pure works for functions using the new syntax -Base.@pure (fpure2(x::T) where T) = T -@test which(fpure2, (Int64,)).pure - # issue #10880 function cat10880(a, b) Tuple{a.parameters..., b.parameters...} @@ -912,28 +898,6 @@ end f20267(x::T20267{T}, y::T) where (T) = f20267(Any[1][1], x.inds) @test Base.return_types(f20267, (Any, Any)) == Any[Union{}] -# issue #20704 -f20704(::Int) = 1 -Base.@pure b20704(@nospecialize(x)) = f20704(x) -@test b20704(42) === 1 -@test_throws MethodError b20704(42.0) - -bb20704() = b20704(Any[1.0][1]) -@test_throws MethodError bb20704() - -v20704() = Val{b20704(Any[1.0][1])} -@test_throws MethodError v20704() -@test Base.return_types(v20704, ()) == Any[Type{Val{1}}] - -Base.@pure g20704(::Int) = 1 -h20704(@nospecialize(x)) = g20704(x) -@test g20704(1) === 1 -@test_throws MethodError h20704(1.2) - -Base.@pure c20704() = (f20704(1.0); 1) -d20704() = c20704() -@test_throws MethodError d20704() - #issue #21065, elision of _apply_iterate when splatted expression is not effect_free function f21065(x,y) println("x=$x, y=$y") @@ -1209,13 +1173,6 @@ let typeargs = Tuple{Type{Int},Type{Int},Type{Int},Type{Int},Type{Int},Type{Int} @test only(Base.return_types(promote_type, typeargs)) === Type{Int} end -# demonstrate that inference must converge -# while doing constant propagation -Base.@pure plus1(x) = x + 1 -f21933(x::Val{T}) where {T} = f(Val(plus1(T))) -code_typed(f21933, (Val{1},)) -Base.return_types(f21933, (Val{1},)) - function count_specializations(method::Method) specs = method.specializations n = count(i -> isassigned(specs, i), 1:length(specs)) @@ -4712,8 +4669,8 @@ end |> only === Type{Float64} global it_count47688 = 0 struct CountsIterate47688{N}; end function Base.iterate(::CountsIterate47688{N}, n=0) where N - global it_count47688 += 1 - n <= N ? (n, n+1) : nothing + global it_count47688 += 1 + n <= N ? (n, n+1) : nothing end foo47688() = tuple(CountsIterate47688{5}()...) bar47688() = foo47688() diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index cfcfc7228b3ed..28713ea857c07 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -360,18 +360,6 @@ struct RealConstrained{T <: Real}; end @test !fully_eliminated(x->(RealConstrained{x}; nothing), Tuple{Int}) @test !fully_eliminated(x->(RealConstrained{x}; nothing), Tuple{Type{Vector{T}} where T}) -# Check that pure functions with non-inlineable results still get deleted -struct Big - x::NTuple{1024, Int} -end -Base.@pure Big() = Big(ntuple(identity, 1024)) -function pure_elim_full() - Big() - nothing -end - -@test fully_eliminated(pure_elim_full, Tuple{}) - # Union splitting of convert f_convert_missing(x) = convert(Int64, x) let ci = code_typed(f_convert_missing, Tuple{Union{Int64, Missing}})[1][1], diff --git a/test/core.jl b/test/core.jl index f1a7c3fafeab3..8af7421ba7501 100644 --- a/test/core.jl +++ b/test/core.jl @@ -15,7 +15,7 @@ include("testenv.jl") for (T, c) in ( (Core.CodeInfo, []), (Core.CodeInstance, [:def, :rettype, :rettype_const, :ipo_purity_bits, :argescapes]), - (Core.Method, [#=:name, :module, :file, :line, :primary_world, :sig, :slot_syms, :external_mt, :nargs, :called, :nospecialize, :nkw, :isva, :pure, :is_for_opaque_closure, :constprop=#]), + (Core.Method, [#=:name, :module, :file, :line, :primary_world, :sig, :slot_syms, :external_mt, :nargs, :called, :nospecialize, :nkw, :isva, :is_for_opaque_closure, :constprop=#]), (Core.MethodInstance, [#=:def, :specTypes, :sparam_vals=#]), (Core.MethodTable, [:module]), (Core.TypeMapEntry, [:sig, :simplesig, :guardsigs, :min_world, :max_world, :func, :isleafsig, :issimplesig, :va]),