From 9badfc22edc73009ab1461f2cf2432842e05b7e5 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 2 Mar 2018 17:13:48 -0500 Subject: [PATCH] lower top-level statements in such a way that the front-end knows their values are not used fixes most false positives in the deprecation for using the value of `.=` --- src/ast.c | 18 +++++++++++++++++- src/jlfrontend.scm | 17 ++++++++++++----- src/julia.h | 1 + src/toplevel.c | 2 +- test/deprecation_exec.jl | 12 ++++++++++++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/ast.c b/src/ast.c index d6c8968350187..84da490035742 100644 --- a/src/ast.c +++ b/src/ast.c @@ -829,7 +829,11 @@ jl_value_t *jl_parse_eval_all(const char *fname, form = jl_expand_macros(form, inmodule, NULL, 0); expression = julia_to_scm(fl_ctx, form); } - expression = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "jl-expand-to-thunk")), expression); + // expand non-final expressions in statement position (value unused) + expression = + fl_applyn(fl_ctx, 1, + symbol_value(symbol(fl_ctx, iscons(cdr_(ast)) ? "jl-expand-to-thunk-stmt" : "jl-expand-to-thunk")), + expression); } jl_get_ptls_states()->world_age = jl_world_counter; form = scm_to_julia(fl_ctx, expression, inmodule); @@ -1115,6 +1119,18 @@ JL_DLLEXPORT jl_value_t *jl_expand(jl_value_t *expr, jl_module_t *inmodule) return expr; } +// expand in a context where the expression value is unused +JL_DLLEXPORT jl_value_t *jl_expand_stmt(jl_value_t *expr, jl_module_t *inmodule) +{ + JL_TIMING(LOWERING); + JL_GC_PUSH1(&expr); + expr = jl_copy_ast(expr); + expr = jl_expand_macros(expr, inmodule, NULL, 0); + expr = jl_call_scm_on_ast("jl-expand-to-thunk-stmt", expr, inmodule); + JL_GC_POP(); + return expr; +} + #ifdef __cplusplus } diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 8dc9a853f5014..9572225af114b 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -94,12 +94,14 @@ (define *in-expand* #f) +(define (toplevel-only-expr? e) + (and (pair? e) + (or (memq (car e) '(toplevel line module import importall using export + error incomplete)) + (and (eq? (car e) 'global) (every symbol? (cdr e)))))) + (define (expand-toplevel-expr e) - (cond ((or (atom? e) - (and (pair? e) - (or (memq (car e) '(toplevel line module import importall using export - error incomplete)) - (and (eq? (car e) 'global) (every symbol? (cdr e)))))) + (cond ((or (atom? e) (toplevel-only-expr? e)) (if (underscore-symbol? e) (syntax-deprecation "underscores as an rvalue" "" #f)) e) @@ -207,6 +209,11 @@ (parser-wrap (lambda () (expand-toplevel-expr expr)))) +(define (jl-expand-to-thunk-stmt expr) + (jl-expand-to-thunk (if (toplevel-only-expr? expr) + expr + `(block ,expr (null))))) + ; run whole frontend on a string. useful for testing. (define (fe str) (expand-toplevel-expr (julia-parse str))) diff --git a/src/julia.h b/src/julia.h index de449173e0100..9b11afdfffd80 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1450,6 +1450,7 @@ JL_DLLEXPORT jl_value_t *jl_parse_string(const char *str, size_t len, JL_DLLEXPORT jl_value_t *jl_load_file_string(const char *text, size_t len, char *filename, jl_module_t *inmodule); JL_DLLEXPORT jl_value_t *jl_expand(jl_value_t *expr, jl_module_t *inmodule); +JL_DLLEXPORT jl_value_t *jl_expand_stmt(jl_value_t *expr, jl_module_t *inmodule); JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str); // external libraries diff --git a/src/toplevel.c b/src/toplevel.c index c3279117dacbe..c8f27868f3ed4 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -228,7 +228,7 @@ jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex) for (int i = 0; i < jl_array_len(exprs); i++) { // process toplevel form ptls->world_age = jl_world_counter; - form = jl_expand(jl_array_ptr_ref(exprs, i), newm); + form = jl_expand_stmt(jl_array_ptr_ref(exprs, i), newm); ptls->world_age = jl_world_counter; (void)jl_toplevel_eval_flex(newm, form, 1, 1); } diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl index 633a65d0a66c5..86ae275dcb0ec 100644 --- a/test/deprecation_exec.jl +++ b/test/deprecation_exec.jl @@ -209,6 +209,18 @@ end # #6080 @test_deprecated r"Syntax `&argument`.*is deprecated" Meta.lower(@__MODULE__, :(ccall(:a, Cvoid, (Cint,), &x))) + @test_logs eval(:(module DotEqualsDep + a=[1,2] + a.=3 + 0 + end)) + @test_logs include_string(@__MODULE__, """ + a=[1,2] + a.=3 + 0""") + @test_deprecated include_string(@__MODULE__, """ + a=[1,2] + a.=3""") end module LogTest