Skip to content

Commit 7be88df

Browse files
committed
Fixes initial() not respecting insincere var-typing
Vars that are typed can actually store ANYTHING. The type is a weak promise that BYOND uses as a guarantee in some contexts (as in statics and constants) but not in others (as in normal variable accesses). It's still pretty sour to me that we're supporting this, but that is indeed the BYOND behaviour.
1 parent 4543a28 commit 7be88df

File tree

3 files changed

+11
-10
lines changed

3 files changed

+11
-10
lines changed

Content.Tests/DMProject/Tests/Const/Folding/InitialFolding.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
/datum/a
55
var/const/explicitly_const = 10
6-
var/not_as_const = "apples"
6+
var/static/not_as_const = "apples"
77

88
/datum/a/field_test()
99
var/const/x = initial(not_as_const)

DMCompiler/DM/DMVariable.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ class DMVariable {
1313
public DMExpression Value;
1414
public DMValueType ValType;
1515

16-
/// <summary>
17-
/// This is something necessary for <see cref="Expressions.Initial.TryAsConstant(out Expressions.Constant)"/> to work correctly. <br/>
18-
/// If a variable has a constant value, and is overridden with a new value, an initial() call is ambiguous, as it may refer to the old value or the new one, <br/>
19-
/// depending on whether the src caller is of the child type or the parent type.
20-
/// </summary>
21-
bool _wasOverriddenWithNewConstant = false;
22-
2316
public DMVariable(DreamPath? type, string name, bool isGlobal, bool isConst, DMValueType valType = DMValueType.Anything) {
2417
Type = type;
2518
Name = name;
@@ -42,14 +35,19 @@ public DMVariable WriteToValue(Expressions.Constant value)
4235
Value = value;
4336
return this;
4437
}
45-
_wasOverriddenWithNewConstant = true;
4638
DMVariable clone = new DMVariable(Type,Name,IsGlobal,IsConst,ValType);
4739
clone.Value = value;
4840
return clone;
4941
}
5042

43+
/// <remarks>
44+
/// Most variables are not safe to take as a constant-value, even in initial(), <br/>
45+
/// because we may be arriving here from a member access that doesn't actually access this DMVariable. <br/>
46+
/// Instead, it may be accessing (through duck-typing) a member someplace here.
47+
/// Check the wording of the ref and read it very carefully: https://www.byond.com/docs/ref/#/operator/%2e
48+
/// </remarks>
5149
public bool SafeToTakeAsConstant() {
52-
return Value != null && (IsConst || !_wasOverriddenWithNewConstant);
50+
return Value != null && (IsConst || IsGlobal); // with statics and consts, the type is "dominant" over the value can can just be taken as constant sometimes.
5351
}
5452

5553
public bool TryAsJsonRepresentation(out object valueJson) {

DMCompiler/DM/Expressions/Builtins.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@ public override bool TryAsConstant(out Constant constant) {
494494
case Dereference memberAccess: {
495495
var obj = DMObjectTree.GetDMObject(memberAccess._expr.Path.GetValueOrDefault());
496496
var variable = obj.GetVariable(memberAccess.PropertyName);
497+
if(variable == null) {
498+
variable = obj.GetGlobalVariable(memberAccess.PropertyName);
499+
}
497500
if (variable != null && variable.SafeToTakeAsConstant()) {
498501
return variable.Value.TryAsConstantWithLocation(out constant, Location);
499502
}

0 commit comments

Comments
 (0)