microsoft / microsoft/AL

You cannot have procedure called Array in a codeunit if there is procedure call without parameters.

Open
#8,170 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accepted al-core-compiler
Dominant language
PowerShell
Stars
881
Forks
285
Avg merge
3d 36m
Merged PRs (30d)
1

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

Image Image

Internal work item: AB#617794

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with repro.zip and the generated C# file linked in the issue, focusing on the Array procedure and the Array.Empty() calls. Reproduce the failure by running report B with the debugger. Done means the AL compiler reports the collision or generated code avoids it so the codeunit can be called without a C# compilation error.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
compilers, devtools
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.