- Notifications
You must be signed in to change notification settings - Fork 269
Description
Hi,
I wanted to create a nice codeunit for querying JSON and automatically handle all nuances like nulls, undefined, etc.
Basically this Rec."DecimalField" := SLEFJson.From(ReceivedJsonObject).Select('$.bla.bla', false).AsDecimal(false).
One of functions was named Array (ensure that JsonToken is array).
We can publish app with such code. However, when we try to call any functions from that codeunit we get error:
[2025-12-10 11:50:01.38] Error: C# compilation has failed for the application object CodeUnit_70429866. The failing c# file name is CA0A22E443AFB0EB0F420EA7689C0972DD7E55E8CE0886179F51206B0FCEAF3E.cs. You can find this file with the associated AL file saved in the C:\ProgramData\Microsoft\Microsoft Dynamics NAV\260\Server\MicrosoftDynamicsNavServer$bc26\apps\compilationerrors folder. Detailed compilation error: C:\ProgramData\Microsoft\Microsoft Dynamics NAV\260\Server\MicrosoftDynamicsNavServer$bc26\apps\metadata\3\CA\CA0A22E443AFB0EB0F420EA7689C0972DD7E55E8CE0886179F51206B0FCEAF3E.cs(1369,153): error CS0119: 'Codeunit70429866.Array(NavScope, bool)' is a method, which is not valid in the given context C:\ProgramData\Microsoft\Microsoft Dynamics NAV\260\Server\MicrosoftDynamicsNavServer$bc26\apps\metadata\3\CA\CA0A22E443AFB0EB0F420EA7689C0972DD7E55E8CE0886179F51206B0FCEAF3E.cs(1448,155): error CS0119: 'Codeunit70429866.Array(NavScope, bool)' is a method, which is not valid in the given context In generated C# code there is call to Array.Empty() and since our function is also in the same scope it shadows the dotnet type Array.
This problem is inside BC platform and even if it is fixed, we would need to upgrade to next BC version to actually use the fix. This will require a workaround on our part - we will rename the procedure to Array_.
My problem is that code is in AppSource right now. I published codeunit that does not even compile and crashes web client when called. It is not used anywhere right now and this codeunit is only meant as an example to take this problem seriously.
I would like the AL compiler to either show error when we use function names that collide with dotnet type names or use more general approach such as adding prefix to the AL function names in generated C# code or using explicit namespaces on global types.
Thanks.
Generated C# code
CA0A22E443AFB0EB0F420EA7689C0972DD7E55E8CE0886179F51206B0FCEAF3E.cs.zip
namespace Microsoft.Dynamics.Nav.BusinessApplication { using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Dynamics.Nav.Common.Language; using Microsoft.Dynamics.Nav.EventSubscription; using Microsoft.Dynamics.Nav.Runtime; using Microsoft.Dynamics.Nav.Runtime.Extensions; using Microsoft.Dynamics.Nav.Runtime.Report; using Microsoft.Dynamics.Nav.Types; using Microsoft.Dynamics.Nav.Types.Exceptions; using Microsoft.Dynamics.Nav.Types.Metadata; [NavCodeunitOptions(0, 0, CodeunitSubType.Normal, false)] [ApplicationObjectId(Microsoft.Dynamics.Nav.Types.ObjectType.CodeUnit, 70429866)] public sealed class Codeunit70429866 : NavCodeunit { // ... [NavFunctionVisibility(FunctionVisibility.External), NavCaption(TranslationKey = "Codeunit 1929092066 - Method 614435978")] [SignatureSpan(85568453069504531L)] [SourceSpans(87538752137134109L, 87820239998812179L, 88101719270555709L, 88664669224108070L, 88946157085786139L, 89227636357529646L, 90072026928119833L, 90353514789797911L, 90634994061541427L, 90916451858448408L, 91197922540257288L)] [NavName("Array")] [MethodId(-1873421450)] [ReturnValue] [LocalsNames("Required", "JsonQuery", "_JsonToken", "HasJsonToken")] [MethodScopeFlags(MethodScopeFlags.IsStackFrame)] public async ValueTask<NavCodeunitHandle> Array(NavScope \u03b3ReturnValueParent, bool required) { ALMethodScope<(bool required, NavCodeunitHandle jsonQuery, NavJsonToken _JsonToken, bool hasJsonToken, NavCodeunitHandle \u03b3retVal)> \u03b3scope = default; try { \u03b3scope = new ALMethodScope<(bool required, NavCodeunitHandle jsonQuery, NavJsonToken _JsonToken, bool hasJsonToken, NavCodeunitHandle \u03b3retVal)>(this, "Array", MethodScopeFlags.None, -1873421450); \u03b3scope.ALStart(); \u03b3scope.Target.jsonQuery = new NavCodeunitHandle(\u03b3scope, 70429866); \u03b3scope.Target._JsonToken = NavJsonToken.Default; \u03b3scope.Target.hasJsonToken = default(bool); \u03b3scope.Target.\u03b3retVal = new NavCodeunitHandle(\u03b3ReturnValueParent, 70429866); \u03b3scope.Target.required = required; { \u03b3scope.StmtHit(0); \u03b3scope.Target.hasJsonToken = true; if (\u03b3scope.CStmtHit(1) & (\u03b3scope.Target.required)) { \u03b3scope.StmtHit(2); \u03b3scope.Target._JsonToken = this.globalJsonToken.ALAsArray().ALAsToken(); } else { \u03b3scope.StmtHit(3); \u03b3scope.Target.hasJsonToken = (await this.IsArray()); if (\u03b3scope.CStmtHit(4) & (\u03b3scope.Target.hasJsonToken)) { \u03b3scope.StmtHit(5); \u03b3scope.Target._JsonToken = this.globalJsonToken; } } \u03b3scope.StmtHit(6); \u03b3scope.Target.jsonQuery.ClearReference(); if (\u03b3scope.CStmtHit(7) & (\u03b3scope.Target.hasJsonToken)) { \u03b3scope.StmtHit(8); await \u03b3scope.Target.jsonQuery.Target.InvokeAsync(173111446, new object[] { true, \u03b3scope.Target._JsonToken }); } \u03b3scope.StmtHit(9); \u03b3scope.Target.\u03b3retVal.ALAssign(\u03b3scope.Target.jsonQuery); return \u03b3scope.Target.\u03b3retVal; } } catch (Exception \u03b1e)when (\u03b3scope?.ALException(\u03b1e, out NavALException \u03b1ale) == true) { throw \u03b1ale; } finally { if (\u03b3scope != default) { \u03b3scope.ALFinally(); \u03b3scope.Dispose(); } } } // ... [NavFunctionVisibility(FunctionVisibility.External), NavCaption(TranslationKey = "Codeunit 1929092066 - Method 1599715712")] [SignatureSpan(187180919685709849L)] [SourceSpans(188025331731136557L, 188306811002880036L, 188869743776563240L, 189151214458372104L)] [NavName("AsJsonArray")] [MethodId(42360034)] [ReturnValue] [LocalsNames("Required")] [MethodScopeFlags(MethodScopeFlags.IsStackFrame)] public async ValueTask<NavJsonArray> AsJsonArray_42360034(bool required) { ALMethodScope<(bool required, NavJsonArray \u03b3retVal)> \u03b3scope = default; try { \u03b3scope = new ALMethodScope<(bool required, NavJsonArray \u03b3retVal)>(this, "AsJsonArray", MethodScopeFlags.None, 42360034); \u03b3scope.ALStart(); \u03b3scope.Target.\u03b3retVal = NavJsonArray.Default; \u03b3scope.Target.required = required; { if (\u03b3scope.CStmtHit(0) & ((!\u03b3scope.Target.required) & (!(await this.IsToken())))) { \u03b3scope.StmtHit(1); \u03b3scope.Target.\u03b3retVal = (ALCompiler.ObjectToExactNavValue<NavJsonArray>(await this.json.Target.InvokeAsync(814186226, Array.Empty<object>()))); return \u03b3scope.Target.\u03b3retVal; } \u03b3scope.StmtHit(2); \u03b3scope.Target.\u03b3retVal = this.globalJsonToken.ALAsArray(); return \u03b3scope.Target.\u03b3retVal; } } catch (Exception \u03b1e)when (\u03b3scope?.ALException(\u03b1e, out NavALException \u03b1ale) == true) { throw \u03b1ale; } finally { if (\u03b3scope != default) { \u03b3scope.ALFinally(); \u03b3scope.Dispose(); } } } // ... } }Minimal code for reproducing the problem - just run report B Test with debugger:
repro.zip
