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); } } }
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); } } }
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); }