Julia's behaviour around closures is among the nicest I've seen:
julia> foo(x, y) = x + y
foo (generic function with 1 method)
julia> bar = x -> foo(x, 1)
#3 (generic function with 1 method)
julia> bar(1)
2
julia> @code_llvm bar(1)
; @ REPL[1]:1 within `#3`
define i64 @"julia_#3_122"(i64 signext %0) #0 {
top:
; ā @ REPL[7]:1 within `foo`
; āā @ int.jl:87 within `+`
%1 = add i64 %0, 1
; āā
ret i64 %1
}
julia> Base.delete_method(@which foo(1,1))
julia> bar(1)
ERROR: MethodError: no method matching foo(::Int64, ::Int64)
Stacktrace:
[1] (::var"#3#4")(x::Int64)
@ Main ./REPL[1]:1
[2] top-level scope
@ REPL[6]:1
julia> @code_llvm bar(1)
; @ REPL[1]:1 within `#3`
; Function Attrs: noreturn
define void @"julia_#3_133"(i64 signext %0) #0 {
top:
%1 = alloca [2 x {}*], align 8
%gcframe2 = alloca [3 x {}*], align 16
%gcframe2.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 0
%.sub = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 0
%2 = bitcast [3 x {}*]* %gcframe2 to i8*
call void @llvm.memset.p0i8.i32(i8* noundef nonnull align 16 dereferenceable(24) %2, i8 0, i32 24, i1 false)
%thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #6
%ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
%ppgcstack = bitcast i8* %ppgcstack_i8 to {}****
%pgcstack = load {}***, {}**** %ppgcstack, align 8
%3 = bitcast [3 x {}*]* %gcframe2 to i64*
store i64 4, i64* %3, align 16
%4 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 1
%5 = bitcast {}** %4 to {}***
%6 = load {}**, {}*** %pgcstack, align 8
store {}** %6, {}*** %5, align 8
%7 = bitcast {}*** %pgcstack to {}***
store {}** %gcframe2.sub, {}*** %7, align 8
%8 = call nonnull {}* @ijl_box_int64(i64 signext %0)
%9 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 2
store {}* %8, {}** %9, align 16
store {}* %8, {}** %.sub, align 8
%10 = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 1
store {}* inttoptr (i64 140053833609312 to {}*), {}** %10, align 8
%11 = call nonnull {}* @ijl_apply_generic({}* inttoptr (i64 140053835183152 to {}*), {}** nonnull %.sub, i32 2)
call void @llvm.trap()
unreachable
}