bicep icon indicating copy to clipboard operation
bicep copied to clipboard

Assigned types should be control-flow sensitive

Open jeskew opened this issue 2 years ago • 2 comments

Is your feature request related to a problem? Please describe. Within a ternary expression, Bicep can sometimes generate spurious diagnostics when a subexpression within the true or false clause interacts with a symbol that should be safe given the check in the if clause of the ternary.

For example, the following snippet:

var db = {
  name: 'db1'
}

resource postgreSQL 'Microsoft.DBForPostgreSQL/servers@2017-12-01' existing = {
  name: 'name'
  resource database 'database' = {
    name: db.name
    properties: {
      charset: contains(db, 'charset') ? db.charset : 'utf8'
      collation: contains(db, 'collation') ? db.collation : 'English_United States.1252'
    }
  }
}

will generate the following diagnostics:

[BCP053 (Error)] The type "object" does not contain property "charset". Available properties include "name".
[BCP053 (Error)] The type "object" does not contain property "collation". Available properties include "name".

Describe the solution you'd like Similar to how C# will recognize that foo is non-null inside of a block that starts with if (foo is not null) {, the Bicep compiler's type inference should take an expression's position in control flow into account when assigning a type to an expression. Given that Bicep does not have guard statements that control entry into blocks, this should primarily impact ternary statements. If possible, flow-sensitive typing should take into account:

  • equality operators
  • comparison operators, and
  • some core functions in the sys namespace (e.g., empty, length, contains, endsWith, startsWith, and negations thereof).

jeskew avatar Oct 11 '23 17:10 jeskew

Related to #3750 (3rd option)

anthony-c-martin avatar Oct 11 '23 19:10 anthony-c-martin

As suggested in #3750, the following should now be a viable workaround:

var db = {
  name: 'db1'
}

resource postgreSQL 'Microsoft.DBForPostgreSQL/servers@2017-12-01' existing = {
  name: 'name'
  resource database 'database' = {
    name: db.name
    properties: {
      charset: db.?charset ?? 'utf8'
      collation: db.?collation ?? 'English_United States.1252'
    }
  }
}

anthony-c-martin avatar May 01 '24 17:05 anthony-c-martin