Azure / bicep

Bicep is a declarative language for describing and deploying Azure resources
MIT License
3.22k stars 746 forks source link

'index' property in objects shouldn't be implicitly overwritten in lambda functions #15154

Open LUATEC opened 6 days ago

LUATEC commented 6 days ago

Bicep version Bicep CLI version 0.29.47

Describe the bug

When I define a new object with a parameter called 'index' and assign a value to this parameter, when I use this in a lambda function such as 'map', I expect: a) a warning to appear that inform me that the parameter 'index' shadows a reserved word used in Bicep lambda functions b) the 'index' parameter is not overwritten unless I explicitly define a parameter called 'index' and pass it into the lambda expression

Instead, the value of the object's 'index' parameter is currently implicitly overwritten to another value.

To Reproduce Steps to reproduce the behavior:

  1. Create a new object with a parameter called 'index' with arbitrary user-defined values.
  2. Use this object in a lambda function such as 'map' without defining a parameter called 'index' in the lambda expression
  3. Verify the value of 'index' is overwritten when accessed by <object-name>.index or <object-name>['index']

Additional context This bug potentially relates to this issue.

anthony-c-martin commented 4 days ago

@LUATEC would you mind sharing a Bicep code sample to illustrate the problem?

LUATEC commented 2 days ago

@anthony-c-martin - sure!

Below's the gist of what I had. IIRC, it would try to associate different Managed Environments with the same Subnet ID. When the word index is changed out for idx, it works as expected.

var props1 = [
  {index: 0, name: 'foo', …}
  {index: 1, name: 'bar', …}
]

param props2 = map( props1, prop =>
  union(prop, {'0': {baz: 1, …}, '1': {baz: 2}, …}['${prop.index}'])
)

resource subnets 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' existing = [
  for prop in props2: {
    name: props.name
    …
  }
]

var nameSubnetIdKVPs = [
  for prop in props2: {
    '${prop.name}': subnets[props.index].id
  }
]

var nameSubnetIdDict = reduce(nameSubnetIdKVPs, {}, (cur, next) => union(cur, next))

resource managedEnvironments 'Microsoft.App/managedEnvironments@2024-03-01' = [
  for prop in props2: {
    name: prop.name
    …
    properties: {
      vnetConfiguration: {
        infrastructureSubnetId: nameSubnetIdDict[prop.name]
        …
      }
    }
  }
]