|
3 | 3 |
|
4 | 4 | using System.Collections.Concurrent;
|
5 | 5 | using System.Collections.Immutable;
|
| 6 | +using Azure.Deployments.Core.Diagnostics; |
6 | 7 | using Azure.Deployments.Templates.Export;
|
7 | 8 | using Bicep.Core.Diagnostics;
|
8 | 9 | using Bicep.Core.Emit;
|
@@ -216,13 +217,15 @@ VariableBlockSyntax block when this.binder.GetParent(block) is LambdaSyntax lamb
|
216 | 217 | });
|
217 | 218 |
|
218 | 219 | public override void VisitTypedLocalVariableSyntax(TypedLocalVariableSyntax syntax)
|
219 |
| - => AssignType(syntax, () => |
| 220 | + => AssignTypeWithDiagnostics(syntax, diagnostics => |
220 | 221 | {
|
221 | 222 | if (typeManager.GetDeclaredType(syntax) is not { } declaredType)
|
222 | 223 | {
|
223 | 224 | return ErrorType.Empty();
|
224 | 225 | }
|
225 | 226 |
|
| 227 | + diagnostics.WriteMultiple(ValidateTypeAssignability(syntax.Type, declaredType)); |
| 228 | + |
226 | 229 | base.VisitTypedLocalVariableSyntax(syntax);
|
227 | 230 |
|
228 | 231 | return declaredType;
|
@@ -521,9 +524,10 @@ public override void VisitTypeDeclarationSyntax(TypeDeclarationSyntax syntax)
|
521 | 524 |
|
522 | 525 | if (declaredType is not null)
|
523 | 526 | {
|
524 |
| - ValidateDecorators(syntax.Decorators, |
525 |
| - declaredType is TypeType wrapped ? wrapped.Unwrapped : declaredType, |
526 |
| - diagnostics); |
| 527 | + var unwrapped = declaredType is TypeType wrapped ? wrapped.Unwrapped : declaredType; |
| 528 | + ValidateDecorators(syntax.Decorators, unwrapped, diagnostics); |
| 529 | + |
| 530 | + diagnostics.WriteMultiple(ValidateTypeAssignability(syntax.Value, unwrapped)); |
527 | 531 | }
|
528 | 532 |
|
529 | 533 | return declaredType ?? ErrorType.Empty();
|
@@ -600,6 +604,8 @@ public override void VisitArrayTypeMemberSyntax(ArrayTypeMemberSyntax syntax)
|
600 | 604 |
|
601 | 605 | base.VisitArrayTypeMemberSyntax(syntax);
|
602 | 606 |
|
| 607 | + diagnostics.WriteMultiple(ValidateTypeAssignability(syntax.Value, declaredType)); |
| 608 | + |
603 | 609 | return declaredType;
|
604 | 610 | });
|
605 | 611 |
|
@@ -878,6 +884,7 @@ private TypeSymbol GetDeclaredTypeAndValidateDecorators(DecorableSyntax targetSy
|
878 | 884 | }
|
879 | 885 |
|
880 | 886 | this.ValidateDecorators(targetSyntax.Decorators, declaredType, diagnostics);
|
| 887 | + diagnostics.WriteMultiple(ValidateTypeAssignability(typeSyntax, declaredType)); |
881 | 888 |
|
882 | 889 | return declaredType;
|
883 | 890 | }
|
@@ -1958,6 +1965,8 @@ public override void VisitTypedLambdaSyntax(TypedLambdaSyntax syntax)
|
1958 | 1965 | CollectErrors(errors, argumentType.Type);
|
1959 | 1966 | }
|
1960 | 1967 |
|
| 1968 | + diagnostics.WriteMultiple(ValidateTypeAssignability(syntax.ReturnType, declaredLambdaType.ReturnType.Type)); |
| 1969 | + |
1961 | 1970 | var returnType = TypeValidator.NarrowTypeAndCollectDiagnostics(typeManager, binder, this.parsingErrorLookup, diagnostics, syntax.Body, declaredLambdaType.ReturnType.Type);
|
1962 | 1971 | CollectErrors(errors, returnType);
|
1963 | 1972 |
|
@@ -2396,6 +2405,43 @@ private IEnumerable<IDiagnostic> ValidateDefaultValue(ParameterDefaultValueSynta
|
2396 | 2405 | return diagnosticWriter.GetDiagnostics();
|
2397 | 2406 | }
|
2398 | 2407 |
|
| 2408 | + private IEnumerable<IDiagnostic> ValidateTypeAssignability(SyntaxBase typeSyntax, TypeSymbol assignedType) |
| 2409 | + { |
| 2410 | + if (typeSyntax is not SkippedTriviaSyntax && |
| 2411 | + assignedType is not ErrorType && |
| 2412 | + TryGetArmPrimitiveType(assignedType, typeSyntax) is null) |
| 2413 | + { |
| 2414 | + yield return DiagnosticBuilder.ForPosition(typeSyntax) |
| 2415 | + .TypeExpressionResolvesToUnassignableType(assignedType); |
| 2416 | + } |
| 2417 | + } |
| 2418 | + |
| 2419 | + private TypeSymbol? TryGetArmPrimitiveType(TypeSymbol type, SyntaxBase syntax) => type switch |
| 2420 | + { |
| 2421 | + BooleanLiteralType or BooleanType => LanguageConstants.Bool, |
| 2422 | + IntegerLiteralType or IntegerType => LanguageConstants.Int, |
| 2423 | + StringLiteralType or StringType => LanguageConstants.String, |
| 2424 | + ResourceType when features.ResourceTypedParamsAndOutputsEnabled => LanguageConstants.String, |
| 2425 | + ObjectType or DiscriminatedObjectType => LanguageConstants.Object, |
| 2426 | + TupleType or ArrayType => LanguageConstants.Array, |
| 2427 | + UnionType when TypeHelper.TryRemoveNullability(type) is { } nonNull => TryGetArmPrimitiveType(nonNull, syntax), |
| 2428 | + UnionType when IsExplicitUnion(syntax) => LanguageConstants.Any, |
| 2429 | + UnionType union when union.Members.Select(m => TryGetArmPrimitiveType(m.Type, syntax)).ToArray() is { } mTypes && |
| 2430 | + !mTypes.Any(t => t is null) && |
| 2431 | + mTypes.ToHashSet() is { } mUniqueTypes && |
| 2432 | + mUniqueTypes.Count == 1 => mUniqueTypes.Single(), |
| 2433 | + _ => null, |
| 2434 | + }; |
| 2435 | + |
| 2436 | + private static bool IsExplicitUnion(SyntaxBase syntax) => syntax switch |
| 2437 | + { |
| 2438 | + UnionTypeSyntax => true, |
| 2439 | + ParenthesizedTypeSyntax parenthesized => IsExplicitUnion(parenthesized.Expression), |
| 2440 | + NonNullableTypeSyntax nonNullable => IsExplicitUnion(nonNullable.Base), |
| 2441 | + NullableTypeSyntax nullable => IsExplicitUnion(nullable.Base), |
| 2442 | + _ => false, |
| 2443 | + }; |
| 2444 | + |
2399 | 2445 | private IEnumerable<IDiagnostic> ValidateIdentifierAccess(SyntaxBase syntax)
|
2400 | 2446 | {
|
2401 | 2447 | return SyntaxAggregator.Aggregate(syntax, new List<IDiagnostic>(), (accumulated, current) =>
|
|
0 commit comments