Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds check for local variable in scope operator check #2227

Merged
merged 8 commits into from
Feb 24, 2025
19 changes: 14 additions & 5 deletions Content.Tests/DMProject/Tests/Operators/scope.dm
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/datum
var/static/datum/three/three
var/text = "hello"

var/static/one = "one"

/datum/three
var/static/datum/four/four
text = "hi"
var/overridden_text = type::text
var/original_text = parent_type::text

/datum/three/proc/typetest()
// initial shorthand, type:: and parent_type::
ASSERT(text == "hi")
Expand All @@ -21,7 +21,7 @@ var/static/one = "one"
ASSERT(src::text == "hi")
ASSERT(src::overridden_text == "hi")
ASSERT(src::original_text == "hello")

// proc reference
ASSERT(__PROC__ == /datum/three::typetest())

Expand All @@ -31,11 +31,17 @@ var/static/one = "one"
/datum/five
var/static/six = "three four five six"

/datum/six
var/price = 60
better
price = parent_type::price + 40

/proc/return_two()
return "two"

/proc/RunTest()
// global vars and procs
var/one = "not one"
ASSERT(::one == "one")
ASSERT(::return_two() == "two")

Expand All @@ -52,10 +58,13 @@ var/static/one = "one"
ASSERT(test::three::four.five::six == "3 4 5 6")
ASSERT(/datum::three::four.five::six == "3 4 5 6")

// this does not compile in BYOND, that is just a bug
// this does not compile in BYOND, that is just a bug
test::three::four.five::six = "7 8 9 10"
ASSERT(test::three::four.five::six == "7 8 9 10")
ASSERT(/datum::three::four.five::six == "7 8 9 10")

var/datum/three/threetest = new
threetest.typetest()

var/datum/six/better/fourtest = new()
ASSERT(fourtest.price == 100)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// COMPILE ERROR OD0011

/datum/thing
var/price = 60
better
proc/test_proc()
price = parent_type::price + 40
15 changes: 10 additions & 5 deletions DMCompiler/DM/Builders/DMExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -644,11 +644,16 @@ private DMExpression BuildScopeIdentifier(DMASTScopeIdentifier scopeIdentifier,
if (scopeIdentifier.Expression is DMASTIdentifier { Identifier: "type" or "parent_type" } identifier) {
// This is the same behaviour as in BYOND, but BYOND simply raises an undefined var error.
// We want to give end users an explanation at least.
if (scopeMode is Normal && ctx.Proc != null)
return BadExpression(WarningCode.BadExpression, identifier.Location,
"Use of \"type::\" and \"parent_type::\" outside of a context is forbidden");

if (identifier.Identifier == "parent_type") {
if (scopeMode is Normal && ctx.Proc != null) {
if (ctx.Proc.GetLocalVariable(identifier.Identifier) != null) {
// actually - it's referring to a local variable named "type" or "parent_type"... just do the usual thing
expression = BuildExpression(scopeIdentifier.Expression, inferredPath);
} else {
return BadExpression(WarningCode.BadExpression, identifier.Location,
"Use of \"type::\" and \"parent_type::\" inside an object proc is only valid when " +
"there is a local variable named \"type\" or \"parent_type\"");
}
} else if (identifier.Identifier == "parent_type") {
if (ctx.Type.Parent == null)
return BadExpression(WarningCode.ItemDoesntExist, identifier.Location,
$"Type {ctx.Type.Path} does not have a parent");
Expand Down
4 changes: 2 additions & 2 deletions DMCompiler/DM/DMExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ private void VerifyArgType(DMCompiler compiler, DMProc targetProc, int index, st
}
}

internal readonly struct ExpressionContext(DMCompiler compiler, DMObject type, DMProc proc) {
internal readonly struct ExpressionContext(DMCompiler compiler, DMObject type, DMProc? proc) {
public readonly DMCompiler Compiler = compiler;
public readonly DMObject Type = type;
public readonly DMProc Proc = proc;
public readonly DMProc? Proc = proc;

public DMObjectTree ObjectTree => Compiler.DMObjectTree;
}
Loading