/// <inheritdoc/> public override Expression ApplyTo(Syntax.BinaryExpression expr, ICompilationContext <TSettings> ctx) { var exprType = expr.Type; var args = expr.Arguments.Select(m => { var origHint = GetTypeHint(ctx); if (exprType.IsComparisonType()) { SetTypeHint(ctx, null); } else if (exprType.IsBooleanType()) { SetTypeHint(ctx, typeof(bool)); } var applied = ApplyTo(m, ctx); SetTypeHint(ctx, origHint); return(applied); }).ToList(); var boolResType = exprType.IsComparisonType() ? typeof(bool) : GetTypeHint(ctx) ?? args.First().Type; try { return(AggregateBinaryExpr(expr.Type, args, boolResType, ctx.Settings)); } catch { // ignore } // if we fail to do it with the base implicitly gotten arguments, attempt to convert all arguments to the same (largest) type var allTypes = args.Select(e => e.Type); var convertAllTo = allTypes .OrderByDescending(CompilerHelpers.EstimateTypeSize) .Where(ty => allTypes.All(t => CompilerHelpers.HasConversionPathTo(t, ty))) .First(); // biggest one boolResType = GetTypeHint(ctx) ?? convertAllTo; // re-compile arguments with new type hint SetTypeHint(ctx, convertAllTo); args = expr.Arguments.Select(m => CompilerHelpers.ConvertToType(ApplyTo(m, ctx), convertAllTo)).ToList(); return(AggregateBinaryExpr(expr.Type, args, boolResType, ctx.Settings)); }
/// <inheritdoc/> public bool TryCompile(IReadOnlyList <MathExpression> arguments, ICompilationContext <object?> ctx, ITypeHintHandler hintHandler, [MaybeNullWhen(false)] out Expression expr) { if (arguments.Count != 3) { expr = null; return(false); } var condition = hintHandler.TransformWithHint(arguments.First(), typeof(bool), ctx); var hint = hintHandler.CurrentHint(ctx); Expression?thenExpr = null, elseExpr = null; Type? convertAllTo, lastThen, lastElse; do { lastThen = thenExpr?.Type; lastElse = elseExpr?.Type; thenExpr = hintHandler.TransformWithHint(arguments[1], hint, ctx); elseExpr = hintHandler.TransformWithHint(arguments[2], hint, ctx); var allTypes = new[] { thenExpr.Type, elseExpr.Type }; convertAllTo = allTypes .OrderByDescending(CompilerHelpers.EstimateTypeSize) .Where(ty => allTypes.All(t => CompilerHelpers.HasConversionPathTo(t, ty))) .FirstOrDefault(); // biggest one }while (thenExpr.Type != elseExpr.Type && thenExpr.Type != convertAllTo && lastThen != thenExpr.Type && lastElse != elseExpr.Type); if (convertAllTo == null) { throw new ArgumentException("True and False branches of condition do not have a common type to be converted to"); } expr = Expression.Condition(CompilerHelpers.AsBoolean(condition), CompilerHelpers.ConvertToType(thenExpr, convertAllTo), CompilerHelpers.ConvertToType(elseExpr, convertAllTo)); return(true); }