public override void VisitParameterDeclarationSyntax(ParameterDeclarationSyntax syntax) => AssignTypeWithDiagnostics(syntax, diagnostics => { diagnostics.AddRange(this.ValidateIdentifierAccess(syntax)); // assume "any" type when the parameter has parse errors (either missing or was skipped) var declaredType = syntax.ParameterType == null ? LanguageConstants.Any : LanguageConstants.TryGetDeclarationType(syntax.ParameterType.TypeName); if (declaredType == null) { return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidParameterType())); } var assignedType = declaredType; if (object.ReferenceEquals(assignedType, LanguageConstants.String)) { var allowedItemTypes = SyntaxHelper.TryGetAllowedItems(syntax)? .Select(item => typeManager.GetTypeInfo(item)); if (allowedItemTypes != null && allowedItemTypes.All(itemType => itemType is StringLiteralType)) { assignedType = UnionType.Create(allowedItemTypes); } } switch (syntax.Modifier) { case ParameterDefaultValueSyntax defaultValueSyntax: diagnostics.AddRange(ValidateDefaultValue(defaultValueSyntax, assignedType)); break; case ObjectSyntax modifierSyntax: var modifierType = LanguageConstants.CreateParameterModifierType(declaredType, assignedType); // we don't need to actually use the narrowed type; just need to use this to collect assignment diagnostics TypeValidator.NarrowTypeAndCollectDiagnostics(typeManager, modifierSyntax, modifierType, diagnostics); break; } return(assignedType); });
public override void VisitParameterDeclarationSyntax(ParameterDeclarationSyntax syntax) { diagnostics.AddRange(this.ValidateIdentifierAccess(syntax)); var assignedType = typeManager.GetTypeInfo(syntax); switch (syntax.Modifier) { case ParameterDefaultValueSyntax defaultValueSyntax: diagnostics.AddRange(ValidateDefaultValue(defaultValueSyntax, assignedType)); break; case ObjectSyntax modifierSyntax: if (assignedType.TypeKind != TypeKind.Error && SyntaxHelper.TryGetPrimitiveType(syntax) is PrimitiveType primitiveType) { var modifierType = LanguageConstants.CreateParameterModifierType(primitiveType, assignedType); diagnostics.AddRange(TypeValidator.GetExpressionAssignmentDiagnostics(typeManager, modifierSyntax, modifierType)); } break; } }
private DeclaredTypeAssignment?GetArrayAccessType(ArrayAccessSyntax syntax) { var baseExpressionAssignment = GetDeclaredTypeAssignment(syntax.BaseExpression); var indexAssignedType = this.typeManager.GetTypeInfo(syntax.IndexExpression); // TODO: Currently array access is broken with discriminated object types - revisit when that is fixed switch (baseExpressionAssignment?.Reference.Type) { case ArrayType arrayType when TypeValidator.AreTypesAssignable(indexAssignedType, LanguageConstants.Int): // we are accessing an array by an expression of a numeric type // return the item type of the array // for regular array we can't evaluate the array index at this point, but for loops the index is irrelevant // and we need to set declaring syntax, so property access can provide completions correctly for resource and module loops var declaringSyntax = baseExpressionAssignment.DeclaringSyntax is ForSyntax { Body : ObjectSyntax loopBody } ? loopBody : null; return(new DeclaredTypeAssignment(arrayType.Item.Type, declaringSyntax));
private TypeSymbol GetArrayAccessType(TypeManagerContext context, ArrayAccessSyntax syntax) { var errors = new List <ErrorDiagnostic>(); var baseType = this.GetTypeInfoInternal(context, syntax.BaseExpression); CollectErrors(errors, baseType); var indexType = this.GetTypeInfoInternal(context, syntax.IndexExpression); CollectErrors(errors, indexType); if (errors.Any() || indexType.TypeKind == TypeKind.Error) { return(new ErrorTypeSymbol(errors)); } if (baseType.TypeKind == TypeKind.Any) { // base expression is of type any if (indexType.TypeKind == TypeKind.Any) { // index is also of type any return(LanguageConstants.Any); } if (TypeValidator.AreTypesAssignable(indexType, LanguageConstants.Int) == true || TypeValidator.AreTypesAssignable(indexType, LanguageConstants.String) == true) { // index expression is string | int but base is any return(LanguageConstants.Any); } // index was of the wrong type return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.IndexExpression).StringOrIntegerIndexerRequired(indexType))); } if (baseType is ArrayType baseArray) { // we are indexing over an array if (TypeValidator.AreTypesAssignable(indexType, LanguageConstants.Int) == true) { // the index is of "any" type or integer type // return the item type return(baseArray.ItemType); } return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.IndexExpression).ArraysRequireIntegerIndex(indexType))); } if (baseType is ObjectType baseObject) { // we are indexing over an object if (indexType.TypeKind == TypeKind.Any) { // index is of type "any" return(GetExpressionedPropertyType(baseObject, syntax.IndexExpression)); } if (TypeValidator.AreTypesAssignable(indexType, LanguageConstants.String) == true) { switch (syntax.IndexExpression) { case StringSyntax @string when @string.IsInterpolated() == false: var propertyName = @string.GetLiteralValue(); return(this.GetNamedPropertyType(baseObject, syntax.IndexExpression, propertyName)); default: // the property name is itself an expression return(this.GetExpressionedPropertyType(baseObject, syntax.IndexExpression)); } } return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.IndexExpression).ObjectsRequireStringIndex(indexType))); } // index was of the wrong type return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.BaseExpression).IndexerRequiresObjectOrArray(baseType))); }
public static BinaryOperatorInfo?TryMatchExact(BinaryOperator @operator, TypeSymbol operandType1, TypeSymbol operandType2) { return(OperatorLookup[@operator] .SingleOrDefault(info => TypeValidator.AreTypesAssignable(operandType1, info.OperandType) == true && TypeValidator.AreTypesAssignable(operandType2, info.OperandType) == true)); }