/*
         * 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);
        }
示例#2
0
 public override void VisitArrayAccessSyntax(ArrayAccessSyntax syntax) =>
 this.BuildWithConcat(() => base.VisitArrayAccessSyntax(syntax));
示例#3
0
        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}");
            }
        }
示例#4
0
 public override void VisitArrayAccessSyntax(ArrayAccessSyntax syntax)
 {
     this.buffer.Append('(');
     base.VisitArrayAccessSyntax(syntax);
     this.buffer.Append(')');
 }
示例#5
0
        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)));
        }