From: Francis De Brabandere <francisdb@gmail.com> Native VBScript accepts a global Dim whose name matches a const from an earlier compile unit and creates a fresh variable that later name lookups resolve to, so the name becomes readable and assignable, while code in the defining compile unit keeps using the inlined const value. Wine skipped the variable creation, so the name kept resolving to the const and assignments failed with an illegal assignment error. --- dlls/vbscript/tests/lang.vbs | 41 ++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.c | 9 +++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index acdd992cbcf..b2e770096f3 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -2915,6 +2915,47 @@ sub TestExecuteGlobalRedim end sub Call TestExecuteGlobalRedim +' A Dim in a later compile unit may shadow a global Const from a prior one: +' it creates a fresh variable that later compile units resolve to, while the +' defining compile unit keeps the inlined const value. +Dim egCrossVal +Const egConst = 26 +ExecuteGlobal "Dim egConst" +ExecuteGlobal "egCrossVal = IsEmpty(egConst) & "" "" & TypeName(egConst)" +Call ok(egCrossVal = "True Empty", "dimmed-over-const fresh read: " & egCrossVal) +ExecuteGlobal "egConst = 5" +ExecuteGlobal "egCrossVal = egConst" +Call ok(egCrossVal = 5, "dimmed-over-const after assign = " & egCrossVal) +Call ok(egConst = 26, "egConst in defining compile unit = " & egConst) + +Const egConst2 = 7 +ExecuteGlobal "Dim egConst2 : egConst2 = 8 : egCrossVal = egConst2" +Call ok(egCrossVal = 8, "dim+assign+read in one compile unit = " & egCrossVal) +Call ok(egConst2 = 7, "egConst2 in defining compile unit = " & egConst2) + +Const egConstArr = 2 +ExecuteGlobal "Dim egConstArr(3)" +ExecuteGlobal "egConstArr(0) = 11 : egCrossVal = egConstArr(0)" +Call ok(egCrossVal = 11, "array dimmed over const element = " & egCrossVal) +Call ok(egConstArr = 2, "egConstArr in defining compile unit = " & egConstArr) + +Sub TestDimOverConstErrors + on error resume next + + err.clear : ExecuteGlobal "Const egConst = 27" + call ok(err.number = 1041, "Const over dimmed-over-const err=" & err.number) + + err.clear : ExecuteGlobal "Const egCrossVal = 1" + call ok(err.number = 1041, "Const over prior Dim err=" & err.number) + + err.clear : ExecuteGlobal "Const egSameParse = 1 : Dim egSameParse" + call ok(err.number = 1041, "same-unit Const+Dim err=" & err.number) + + err.clear : ExecuteGlobal "Dim egSameParse2 : Const egSameParse2 = 1" + call ok(err.number = 1041, "same-unit Dim+Const err=" & err.number) +end sub +Call TestDimOverConstErrors + Class FixedClassArr Private mArr(2) Public LastErr diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index ff28b3b17ef..f2c00b9cf28 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -140,7 +140,12 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL for (i = 0; i < code->main_code.var_cnt; i++) { - if (script_disp_find_var(obj, code->main_code.vars[i].name)) + dynamic_var_t *existing = script_disp_find_var(obj, code->main_code.vars[i].name); + + /* A Dim may shadow a const from a previous compile unit: it creates a + fresh variable that name lookups resolve to from now on, while the + defining compile unit keeps using the inlined const value. */ + if (existing && !existing->is_const) continue; if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var)))) @@ -153,6 +158,8 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL var->is_const = FALSE; var->array = NULL; var->index = obj->global_vars_cnt; + if (existing) + rb_remove(&obj->var_tree, &existing->entry); rb_put(&obj->var_tree, var->name, &var->entry); obj->global_vars[obj->global_vars_cnt++] = var; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11121