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

No more warnings when assigning value of "any" type to a discriminator property #3805

Merged
merged 2 commits into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/Bicep.Core.IntegrationTests/ScenarioTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2355,5 +2355,40 @@ public void Test_Issue3566()

result.Should().NotHaveAnyDiagnostics();
}

// https://github.com/Azure/bicep/issues/3617
[TestMethod]
public void Test_Issue3617()
{
var result = CompilationHelper.Compile(@"
param eventGridSystemTopicName string
param subscription object
param endPointPropertiesWithIdentity object
param endPointProperties object
param defaultAdvancedFilterObject object

resource eventSubscription 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2020-10-15-preview' = {
name: '${eventGridSystemTopicName}/${subscription.name}'
properties: {
deliveryWithResourceIdentity: subscription.destination.useIdentity ? endPointPropertiesWithIdentity[toLower(subscription.destination.type)] : null
destination: subscription.destination.useIdentity ? null : endPointProperties[toLower(subscription.destination.type)]
filter: {
subjectBeginsWith: subscription.filter.beginsWith
subjectEndsWith: subscription.filter.endsWith
includedEventTypes: subscription.filter.eventTypes
isSubjectCaseSensitive: subscription.filter.caseSensitive
enableAdvancedFilteringOnArrays: subscription.filter.enableAdvancedFilteringOnArrays
advancedFilters: [for advancedFilter in subscription.filter.advancedFilters: {
key: advancedFilter.key
operatorType: advancedFilter.operator
value: union(defaultAdvancedFilterObject, advancedFilter).value
values: union(defaultAdvancedFilterObject, advancedFilter).values
}]
}
}
}
");
result.Should().NotHaveAnyDiagnostics();
}
}
}
65 changes: 35 additions & 30 deletions src/Bicep.Core/TypeSystem/TypeValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,45 +377,50 @@ private TypeSymbol NarrowDiscriminatedObjectType(TypeValidatorConfig config, Obj
// Let's not do this just yet, and see if a use-case arises.

var discriminatorType = typeManager.GetTypeInfo(discriminatorProperty.Value);
if (discriminatorType is not StringLiteralType stringLiteralDiscriminator)
switch(discriminatorType)
{
diagnosticWriter.Write(
config.OriginSyntax ?? expression,
x => x.PropertyTypeMismatch(ShouldWarn(targetType), TryGetSourceDeclaration(config), targetType.DiscriminatorKey, targetType.DiscriminatorKeysUnionType, discriminatorType));
return LanguageConstants.Any;
}
case AnyType:
return LanguageConstants.Any;

if (!targetType.UnionMembersByKey.TryGetValue(stringLiteralDiscriminator.Name, out var selectedObjectReference))
{
// no matches
var discriminatorCandidates = targetType.UnionMembersByKey.Keys.OrderBy(x => x);
bool shouldWarn = ShouldWarn(targetType);

diagnosticWriter.Write(
config.OriginSyntax ?? discriminatorProperty.Value,
x =>
case StringLiteralType stringLiteralDiscriminator:
if (!targetType.UnionMembersByKey.TryGetValue(stringLiteralDiscriminator.Name, out var selectedObjectReference))
{
var sourceDeclaration = TryGetSourceDeclaration(config);

if (sourceDeclaration is null && SpellChecker.GetSpellingSuggestion(stringLiteralDiscriminator.Name, discriminatorCandidates) is { } suggestion)
{
// no matches
var discriminatorCandidates = targetType.UnionMembersByKey.Keys.OrderBy(x => x);
bool shouldWarn = ShouldWarn(targetType);

diagnosticWriter.Write(
config.OriginSyntax ?? discriminatorProperty.Value,
x =>
{
var sourceDeclaration = TryGetSourceDeclaration(config);

if (sourceDeclaration is null && SpellChecker.GetSpellingSuggestion(stringLiteralDiscriminator.Name, discriminatorCandidates) is { } suggestion)
{
// only look up suggestions if we're not sourcing this type from another declaration.
return x.PropertyStringLiteralMismatchWithSuggestion(shouldWarn, targetType.DiscriminatorKey, targetType.DiscriminatorKeysUnionType, stringLiteralDiscriminator.Name, suggestion);
}
}

return x.PropertyTypeMismatch(shouldWarn, sourceDeclaration, targetType.DiscriminatorKey, targetType.DiscriminatorKeysUnionType, discriminatorType);
});
return x.PropertyTypeMismatch(shouldWarn, sourceDeclaration, targetType.DiscriminatorKey, targetType.DiscriminatorKeysUnionType, discriminatorType);
});

return LanguageConstants.Any;
}
return LanguageConstants.Any;
}

if (selectedObjectReference.Type is not ObjectType selectedObjectType)
{
throw new InvalidOperationException($"Discriminated type {targetType.Name} contains non-object member");
}
if (selectedObjectReference.Type is not ObjectType selectedObjectType)
{
throw new InvalidOperationException($"Discriminated type {targetType.Name} contains non-object member");
}

// we have a match!
return NarrowObjectType(config, expression, selectedObjectType);

// we have a match!
return NarrowObjectType(config, expression, selectedObjectType);
default:
diagnosticWriter.Write(
config.OriginSyntax ?? expression,
x => x.PropertyTypeMismatch(ShouldWarn(targetType), TryGetSourceDeclaration(config), targetType.DiscriminatorKey, targetType.DiscriminatorKeysUnionType, discriminatorType));
return LanguageConstants.Any;
}
}

private TypeSymbol NarrowObjectType(TypeValidatorConfig config, ObjectSyntax expression, ObjectType targetType)
Expand Down