예제 #1
0
        public IEnumerable <Decorator> GetMatches(FunctionSymbol symbol, IList <TypeSymbol> argumentTypes)
        {
            foreach (var overload in FunctionResolver.GetMatches(symbol, argumentTypes, out var _, out var _))
            {
                var decorator = this.TryGetDecorator(overload);

                if (decorator != null)
                {
                    yield return(decorator);
                }
            }
        }
예제 #2
0
        public IEnumerable <Decorator> GetMatches(FunctionSymbol symbol, IList <TypeSymbol> argumentTypes)
        {
            if (!functionSymbols.Contains(symbol))
            {
                yield break;
            }

            foreach (var overload in FunctionResolver.GetMatches(symbol, argumentTypes, out var _, out var _))
            {
                this.decoratorsByOverloads.TryGetValue(overload, out Decorator? decorator);

                if (decorator != null)
                {
                    yield return(decorator);
                }
            }
        }
예제 #3
0
        private TypeSymbol GetFunctionSymbolType(
            FunctionCallSyntax syntax,
            FunctionSymbol function,
            ImmutableArray <FunctionArgumentSyntax> argumentSyntaxes,
            IList <TypeSymbol> argumentTypes,
            IList <ErrorDiagnostic> errors)
        {
            // Recover argument type errors so we can continue type checking for the parent function call.
            var recoveredArgumentTypes = argumentTypes
                                         .Select(t => t.TypeKind == TypeKind.Error ? LanguageConstants.Any : t)
                                         .ToList();

            var matches = FunctionResolver.GetMatches(
                function,
                recoveredArgumentTypes,
                out IList <ArgumentCountMismatch> countMismatches,
                out IList <ArgumentTypeMismatch> typeMismatches).ToList();

            if (matches.Count == 0)
            {
                if (typeMismatches.Any())
                {
                    if (typeMismatches.Count > 1 && typeMismatches.Skip(1).All(tm => tm.ArgumentIndex == typeMismatches[0].ArgumentIndex))
                    {
                        // All type mismatches are equally good (or bad).
                        var parameterTypes = typeMismatches.Select(tm => tm.ParameterType).ToList();
                        var argumentType   = typeMismatches[0].ArgumentType;
                        var signatures     = typeMismatches.Select(tm => tm.Source.TypeSignature).ToList();
                        var argumentSyntax = argumentSyntaxes[typeMismatches[0].ArgumentIndex];

                        errors.Add(DiagnosticBuilder.ForPosition(argumentSyntax).CannotResolveFunctionOverload(signatures, argumentType, parameterTypes));
                    }
                    else
                    {
                        // Choose the type mismatch that has the largest index as the best one.
                        var(_, argumentIndex, argumentType, parameterType) = typeMismatches.OrderBy(tm => tm.ArgumentIndex).Last();

                        errors.Add(DiagnosticBuilder.ForPosition(argumentSyntaxes[argumentIndex]).ArgumentTypeMismatch(argumentType, parameterType));
                    }
                }
                else
                {
                    // Argument type mismatch wins over count mismatch. Handle count mismatch only when there's no type mismatch.
                    var(actualCount, mininumArgumentCount, maximumArgumentCount) = countMismatches.Aggregate(ArgumentCountMismatch.Reduce);
                    var argumentsSpan = TextSpan.Between(syntax.OpenParen, syntax.CloseParen);

                    errors.Add(DiagnosticBuilder.ForPosition(argumentsSpan).ArgumentCountMismatch(actualCount, mininumArgumentCount, maximumArgumentCount));
                }
            }

            if (errors.Any())
            {
                return(new ErrorTypeSymbol(errors));
            }

            if (matches.Count == 1)
            {
                // we have an exact match or a single ambiguous match
                // return its type
                return(matches.Single().ReturnType);
            }

            // function arguments are ambiguous (due to "any" type)
            // technically, the correct behavior would be to return a union of all possible types
            // unfortunately our language lacks a good type checking construct
            // and we also don't want users to have to use the converter functions to work around it
            // instead, we will return the "any" type to short circuit the type checking for those cases
            return(LanguageConstants.Any);
        }