From ac01e7c47bc75d27e93106e9fb6ee13eabdc1606 Mon Sep 17 00:00:00 2001 From: wixoa Date: Mon, 20 Jan 2025 23:57:37 -0500 Subject: [PATCH] Fix overriding runtime-initialized vars with constants (#2176) --- DMCompiler/DM/DMCodeTree.Vars.cs | 12 +++++++----- DMCompiler/DM/DMObject.cs | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/DMCompiler/DM/DMCodeTree.Vars.cs b/DMCompiler/DM/DMCodeTree.Vars.cs index 667b96cbfd..f7ff73d79c 100644 --- a/DMCompiler/DM/DMCodeTree.Vars.cs +++ b/DMCompiler/DM/DMCodeTree.Vars.cs @@ -43,13 +43,15 @@ protected void SetVariableValue(DMCompiler compiler, DMObject dmObject, DMVariab if (value.TryAsConstant(compiler, out var constant)) { variable.Value = constant; - return; + + // We want to continue with putting this in the init proc if a base type initializes it to another value + if (!isOverride || !dmObject.IsRuntimeInitialized(variable.Name)) { + return; + } } else if (variable.IsConst) { compiler.Emit(WarningCode.HardConstContext, value.Location, "Value of const var must be a constant"); return; - } - - if (!IsValidRightHandSide(compiler, dmObject, value)) { + } else if (!IsValidRightHandSide(compiler, dmObject, value)) { compiler.Emit(WarningCode.BadExpression, value.Location, $"Invalid initial value for \"{variable.Name}\""); return; @@ -60,7 +62,7 @@ protected void SetVariableValue(DMCompiler compiler, DMObject dmObject, DMVariab var assign = new Assignment(initLoc, field, value); variable.Value = new Null(Location.Internal); - dmObject.InitializationProcExpressions.Add(assign); + dmObject.InitializationProcAssignments.Add((variable.Name, assign)); } /// Whether the given value can be used as an instance variable's initial value diff --git a/DMCompiler/DM/DMObject.cs b/DMCompiler/DM/DMObject.cs index d48d84eb6f..10834f8433 100644 --- a/DMCompiler/DM/DMObject.cs +++ b/DMCompiler/DM/DMObject.cs @@ -1,4 +1,6 @@ -using DMCompiler.Bytecode; +using System.Linq; +using DMCompiler.Bytecode; +using DMCompiler.DM.Expressions; using DMCompiler.Json; namespace DMCompiler.DM; @@ -21,7 +23,7 @@ internal sealed class DMObject(DMCompiler compiler, int id, DreamPath path, DMOb public int? InitializationProc; /// A list of var and verb initializations implicitly done before the user's New() is called. - public readonly List InitializationProcExpressions = new(); + public readonly List<(string Name, Assignment Assignment)> InitializationProcAssignments = new(); public bool IsRoot => Path == DreamPath.Root; @@ -133,6 +135,11 @@ public void AddGlobalVariable(DMVariable global, int id) { TmpVariables.Add(global.Name); } + public bool IsRuntimeInitialized(string varName) { + return InitializationProcAssignments.Any(v => v.Name == varName) + || (Parent?.IsRuntimeInitialized(varName) ?? false); + } + /// /// Recursively searches for a global/static with the given name. /// @@ -152,16 +159,16 @@ public DMComplexValueType GetReturnType(string name) { } public void CreateInitializationProc() { - if (InitializationProcExpressions.Count <= 0 || InitializationProc != null) + if (InitializationProcAssignments.Count <= 0 || InitializationProc != null) return; var init = compiler.DMObjectTree.CreateDMProc(this, null); InitializationProc = init.Id; init.Call(DMReference.SuperProc, DMCallArgumentsType.None, 0); - foreach (DMExpression expression in InitializationProcExpressions) { - init.DebugSource(expression.Location); - expression.EmitPushValue(new(compiler, this, init)); + foreach (var assignment in InitializationProcAssignments) { + init.DebugSource(assignment.Assignment.Location); + assignment.Assignment.EmitPushValue(new(compiler, this, init)); } }