/* * Overrides below correspond to nodes whose presence guarantees that * the expression is not a compile-time constant (assuming constant folding is not performed) * * When the visitor logs an error, it should not visit child nodes as that could lead to redundant errors. */ public override void VisitArrayAccessSyntax(ArrayAccessSyntax syntax) { this.AppendError(syntax); }
public override void VisitArrayAccessSyntax(ArrayAccessSyntax syntax) => this.BuildWithConcat(() => base.VisitArrayAccessSyntax(syntax));
private LanguageExpression ConvertFunction(FunctionCallSyntaxBase functionCall) { var symbol = context.SemanticModel.GetSymbolInfo(functionCall); if (symbol is FunctionSymbol functionSymbol && context.SemanticModel.TypeManager.GetMatchedFunctionOverload(functionCall) is FunctionOverload functionOverload && functionOverload.Evaluator is not null) { return(ConvertExpression(functionOverload.Evaluator(functionCall, symbol, context.SemanticModel.GetTypeInfo(functionCall)))); } switch (functionCall) { case FunctionCallSyntax function: return(CreateFunction( function.Name.IdentifierName, function.Arguments.Select(a => ConvertExpression(a.Expression)))); case InstanceFunctionCallSyntax instanceFunctionCall: var(baseSymbol, indexExpression) = instanceFunctionCall.BaseExpression switch { ArrayAccessSyntax arrayAccessSyntax => (context.SemanticModel.GetSymbolInfo(arrayAccessSyntax.BaseExpression), arrayAccessSyntax.IndexExpression), _ => (context.SemanticModel.GetSymbolInfo(instanceFunctionCall.BaseExpression), null), }; switch (baseSymbol) { case INamespaceSymbol namespaceSymbol: Debug.Assert(indexExpression is null, "Indexing into a namespace should have been blocked by type analysis"); return(CreateFunction( instanceFunctionCall.Name.IdentifierName, instanceFunctionCall.Arguments.Select(a => ConvertExpression(a.Expression)))); case ResourceSymbol resourceSymbol when context.SemanticModel.ResourceMetadata.TryLookup(resourceSymbol.DeclaringSyntax) is { } resource: if (instanceFunctionCall.Name.IdentifierName.StartsWithOrdinalInsensitively("list")) { var converter = indexExpression is not null? CreateConverterForIndexReplacement(resource.NameSyntax, indexExpression, instanceFunctionCall) : this; // Handle list<method_name>(...) method on resource symbol - e.g. stgAcc.listKeys() var convertedArgs = instanceFunctionCall.Arguments.SelectArray(a => ConvertExpression(a.Expression)); var resourceIdExpression = converter.GetFullyQualifiedResourceId(resource); var apiVersion = resource.TypeReference.ApiVersion ?? throw new InvalidOperationException($"Expected resource type {resource.TypeReference.FormatName()} to contain version"); var apiVersionExpression = new JTokenExpression(apiVersion); var listArgs = convertedArgs.Length switch { 0 => new LanguageExpression[] { resourceIdExpression, apiVersionExpression, }, _ => new LanguageExpression[] { resourceIdExpression, }.Concat(convertedArgs), }; return(CreateFunction(instanceFunctionCall.Name.IdentifierName, listArgs)); } break; } throw new InvalidOperationException($"Unrecognized base expression {baseSymbol?.Kind}"); default: throw new NotImplementedException($"Cannot emit unexpected expression of type {functionCall.GetType().Name}"); } }
public override void VisitArrayAccessSyntax(ArrayAccessSyntax syntax) { this.buffer.Append('('); base.VisitArrayAccessSyntax(syntax); this.buffer.Append(')'); }
private TypeSymbol GetArrayAccessType(ArrayAccessSyntax syntax) { var errors = new List <ErrorDiagnostic>(); var baseType = this.GetTypeInfo(syntax.BaseExpression); CollectErrors(errors, baseType); var indexType = this.GetTypeInfo(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))); }