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

Type system reflection error #7295

Open
itpropro opened this issue Jun 18, 2022 · 3 comments
Open

Type system reflection error #7295

itpropro opened this issue Jun 18, 2022 · 3 comments
Labels
bug Something isn't working investigate type system

Comments

@itpropro
Copy link
Contributor

itpropro commented Jun 18, 2022

Bicep version
Bicep CLI version 0.7.4 (5afc312)

Describe the bug
I use modules from the CARML and my own and they all use the following to generate managed identity objects to be used in the template:

@description('Optional. Enables system assigned managed identity on the resource.')
param systemAssignedIdentity bool = false

@description('Optional. The ID(s) to assign to the resource.')
param userAssignedIdentities object = {}
...
var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None')

var identity = identityType != 'None' ? {
  type: identityType
  userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null
} : null

If I have a submodule where I just want to hand over the generated identity object instead of copying the same logic again, I get the following error:

module xyz 'xyz' = [for element in elements: {
  name: element.name
  params: {
    ...
    identity: !empty(identity) ? identity : {}
    ...
  }
}]
// Error:
var identity: null | object
The property "identity" expected a value of type "object" but the provided value is of type "null | object | object".bicep(BCP036)

That error is correct, but when I update the statement to reflect the null state:

identity: ((identity != null) && !empty(identity)) ? identity : {}

It still throws the same error: The property "identity" expected a value of type "object" but the provided value is of type "null | object | object".bicep(BCP036)

To Reproduce
Use the above code

image

@brwilkinson
Copy link
Collaborator

brwilkinson commented Jun 23, 2022

@itpropro

If you are looking for a way to make this scenario work to pass to the Module, you can use an alternate default than null.

@description('Optional. Enables system assigned managed identity on the resource.')
param systemAssignedIdentity bool = false

@description('Optional. The ID(s) to assign to the resource.')
param userAssignedIdentities object = {}

var identityType = systemAssignedIdentity ? (!empty(userAssignedIdentities) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') : (!empty(userAssignedIdentities) ? 'UserAssigned' : 'None')

var identity = identityType != 'None' ? {
  type: identityType
  userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null
} : {}  // <-- default to empty object instead

module xyz 'xyx.bicep' = {
  name: 'myModule01'
  params: {
    identity: identity
    location: resourceGroup().location
  }
}

Then inside of the Module, have the default, plus if it's empty convert it back to null.

xyx.bicep

param identity object = {}

@description('Required. Name of the static site.')
@minLength(1)
@maxLength(40)
param name string = 'mystaticTest54'

@allowed([
  'Free'
  'Standard'
])
@description('Optional. Type of static site to deploy.')
param sku string = 'Free'

@description('Location to deploy static site. The following locations are supported: CentralUS, EastUS2, EastAsia, WestEurope, WestUS2.')
param location string

resource staticSite 'Microsoft.Web/staticSites@2021-03-01' = {
  name: name
  location: location
  identity: identity == {} ? null : identity
  sku: {
    name: sku
    tier: sku
  }
  properties: {}
}

@itpropro
Copy link
Contributor Author

Thanks @brwilkinson for the suggestion, I already use that workaround at many points.
But mostly it's just a workaround for missing features/bugs in the reflection system.
With the statement identity: ((identity != null) && !empty(identity)) ? identity : {}, the Bicep compiler should definitely know that the value can't be null and thereby adjusting it internal type representation, as e.g. TypeScript would do.

@jeskew
Copy link
Member

jeskew commented Oct 16, 2023

The particular scenario outlined will now emit a warning rather than an error, and there are a couple of ways to manually suppress it. You can use a non-null assertion to tell the compiler it's wrong and that the value won't be null:

module xyz 'xyz' = [for element in elements: {
  name: element.name
  params: {
    ...
    identity: !empty(identity) ? identity! : {}
    ...
  }
}]

or you can disable the type mismatch diagnostic altogether (NB: #disable-next-line will only work on warnings, not errors):

module xyz 'xyz' = [for element in elements: {
  name: element.name
  params: {
    ...
    #disable-next-line BCP321
    identity: !empty(identity) ? identity : {}
    ...
  }
}]

The compiler could infer that identity won't be null from context, but this is not yet implemented. (tracked in #12121)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working investigate type system
Projects
None yet
Development

No branches or pull requests

5 participants