diff --git a/Content.Tests/DMProject/Tests/Operators/scope.dm b/Content.Tests/DMProject/Tests/Operators/scope.dm index d0d144128f..5147848801 100644 --- a/Content.Tests/DMProject/Tests/Operators/scope.dm +++ b/Content.Tests/DMProject/Tests/Operators/scope.dm @@ -1,7 +1,7 @@ /datum var/static/datum/three/three var/text = "hello" - + var/static/one = "one" /datum/three @@ -9,7 +9,7 @@ var/static/one = "one" 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") @@ -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()) @@ -31,11 +31,17 @@ var/static/one = "one" /datum/five var/static/six = "three four five six" +/datum/six + var/toughness = 100 + reinforced + toughness = parent_type::toughness + 50 + /proc/return_two() return "two" /proc/RunTest() // global vars and procs + var/one = "not one" ASSERT(::one == "one") ASSERT(::return_two() == "two") @@ -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/reinforced/fourtest = new() + ASSERT(fourtest.toughness == 150) \ No newline at end of file diff --git a/Content.Tests/DMProject/Tests/Operators/scope_parent_type_fails.dm b/Content.Tests/DMProject/Tests/Operators/scope_parent_type_fails.dm new file mode 100644 index 0000000000..dad6979632 --- /dev/null +++ b/Content.Tests/DMProject/Tests/Operators/scope_parent_type_fails.dm @@ -0,0 +1,7 @@ +// COMPILE ERROR OD0011 + +/datum/armor + var/toughness = 100 + reinforced + proc/test_proc() + toughness = parent_type::toughness + 50 \ No newline at end of file diff --git a/DMCompiler/Compiler/CompilerError.cs b/DMCompiler/Compiler/CompilerError.cs index 2209b23747..62f07718cc 100644 --- a/DMCompiler/Compiler/CompilerError.cs +++ b/DMCompiler/Compiler/CompilerError.cs @@ -43,6 +43,7 @@ public enum WarningCode { // 2000 - 2999 are reserved for compiler configuration of actual behaviour. SoftReservedKeyword = 2000, // For keywords that SHOULD be reserved, but don't have to be. 'null' and 'defined', for instance + ScopeOperandNamedType = 2001, // Scope operator is used on a var named type or parent_type, maybe unintentionally DuplicateVariable = 2100, DuplicateProcDefinition = 2101, PointlessParentCall = 2205, diff --git a/DMCompiler/DM/Builders/DMExpressionBuilder.cs b/DMCompiler/DM/Builders/DMExpressionBuilder.cs index 9ef101ba4a..68452219d2 100644 --- a/DMCompiler/DM/Builders/DMExpressionBuilder.cs +++ b/DMCompiler/DM/Builders/DMExpressionBuilder.cs @@ -644,11 +644,18 @@ 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 + Compiler.Emit(WarningCode.ScopeOperandNamedType, identifier.Location, + $"Using scope operator :: on a variable named \"type\" or \"parent_type\" is ambiguous. Consider changing the variable name from \"{identifier.Identifier}\"."); + 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"); diff --git a/DMCompiler/DMStandard/DefaultPragmaConfig.dm b/DMCompiler/DMStandard/DefaultPragmaConfig.dm index 125a11f244..15f439f14d 100644 --- a/DMCompiler/DMStandard/DefaultPragmaConfig.dm +++ b/DMCompiler/DMStandard/DefaultPragmaConfig.dm @@ -15,6 +15,7 @@ //2000-2999 #pragma SoftReservedKeyword error +#pragma ScopeOperandNamedType warning #pragma DuplicateVariable warning #pragma DuplicateProcDefinition error #pragma PointlessParentCall warning