/// <summary> /// Visits the specified binary expression. /// </summary> /// <param name="binaryExpression">The binary expression.</param> public override Node Visit(BinaryExpression binaryExpression) { base.Visit(binaryExpression); var leftType = binaryExpression.Left.TypeInference.TargetType; var rightType = binaryExpression.Right.TypeInference.TargetType; // No need to log an error as it has been done by the initial base.Visit( if (leftType == null || rightType == null) { return(binaryExpression); } switch (binaryExpression.Operator) { case BinaryOperator.Multiply: binaryExpression.TypeInference.TargetType = GetMultiplyImplicitConversionType(binaryExpression.Span, leftType, rightType); break; case BinaryOperator.Divide: binaryExpression.TypeInference.TargetType = GetDivideImplicitConversionType(binaryExpression.Span, leftType, rightType); break; case BinaryOperator.Minus: case BinaryOperator.Plus: case BinaryOperator.Modulo: case BinaryOperator.LogicalAnd: case BinaryOperator.LogicalOr: case BinaryOperator.BitwiseOr: case BinaryOperator.BitwiseAnd: case BinaryOperator.BitwiseXor: case BinaryOperator.RightShift: case BinaryOperator.LeftShift: binaryExpression.TypeInference.TargetType = GetBinaryImplicitConversionType(binaryExpression.Span, leftType, rightType, false); break; case BinaryOperator.Less: case BinaryOperator.LessEqual: case BinaryOperator.Greater: case BinaryOperator.GreaterEqual: case BinaryOperator.Equality: case BinaryOperator.Inequality: var returnType = GetBinaryImplicitConversionType(binaryExpression.Span, leftType, rightType, true); binaryExpression.TypeInference.TargetType = TypeBase.CreateWithBaseType(returnType, ScalarType.Bool); break; } return(binaryExpression); }
protected virtual void Visit(UnaryExpression unaryExpression) { Visit((Node)unaryExpression); // TODO check for unaryExpression.TypeInference = (TypeInference)unaryExpression.Expression.TypeInference.Clone(); // If this is a logical not, transform the value to a bool (bool2 bool3 bool4 / matrix<bool,1,1> matrix<bool,1,2> ..etc. var subType = unaryExpression.Expression.TypeInference.TargetType; if (subType != null && unaryExpression.Operator == UnaryOperator.LogicalNot) { unaryExpression.TypeInference.TargetType = TypeBase.CreateWithBaseType(subType, ScalarType.Bool); } }
/// <summary> /// Pres the process method invocation. /// </summary> /// <param name="expression">The expression.</param> /// <param name="methodName">Name of the method.</param> /// <param name="declarations">The declarations.</param> /// <returns></returns> protected virtual void ProcessMethodInvocation(MethodInvocationExpression expression, string methodName, List <IDeclaration> declarations) { // Get all arguments types infered var argumentTypeInferences = expression.Arguments.Select(x => x.TypeInference).ToArray(); var argumentTypes = expression.Arguments.Select(x => x.TypeInference.TargetType).ToArray(); // If any type could not be resolved previously, there is already an error, so return immediately if (argumentTypes.Any(x => x == null)) { return; } var overloads = new List <FunctionOverloadScore>(); // Use the most overriden method // TODO: Temporary workaround for user methods overriding builtin methods // Remove the builtin methods if there is any overriding var methodsDeclared = declarations.OfType <MethodDeclaration>().ToList(); for (int i = 0; i < methodsDeclared.Count - 1; i++) { var leftMethod = methodsDeclared[i]; for (int j = i + 1; j < methodsDeclared.Count; j++) { if (leftMethod.IsSameSignature(methodsDeclared[j])) { methodsDeclared.RemoveAt(i); i--; break; } } } // Try to match the function arguments with every overload foreach (var methodDeclaration in methodsDeclared) { var returnType = methodDeclaration.ReturnType.ResolveType(); var parameterTypes = methodDeclaration.Parameters.Select(x => x.Type.ResolveType()).ToArray(); // Number of parameters doesn't match if (argumentTypes.Length > parameterTypes.Length) { continue; } // Check for method calls that is using implicit parameter value if (argumentTypes.Length < parameterTypes.Length) { bool allRemainingParametersHaveDefaultValues = true; // Check for default values for (int i = argumentTypes.Length; i < parameterTypes.Length; i++) { if (methodDeclaration.Parameters[i].InitialValue == null) { allRemainingParametersHaveDefaultValues = false; break; } } // If remaining parameters doesn't have any default values, then continue if (!allRemainingParametersHaveDefaultValues) { continue; } } // Higher score = more conversion (score == 0 is perfect match) int score = 0; bool validOverload = true; // Check parameters for (int i = 0; i < argumentTypes.Length && validOverload; ++i) { var argType = argumentTypes[i]; var expectedType = parameterTypes[i]; var argTypeBase = TypeBase.GetBaseType(argType); var expectedTypeBase = TypeBase.GetBaseType(expectedType); if (expectedTypeBase is GenericParameterType) { var genericParameterType = (GenericParameterType)expectedTypeBase; // TODO handle dynamic score from constraint. if (methodDeclaration.CheckConstraint(genericParameterType, argType)) { score++; } else { validOverload = false; } } else { // TODO, improve the whole test by using TypeBase equality when possible // Then work on scalar type conversion ( float to int, signed to unsigned, different type) var fromScalarType = argTypeBase as ScalarType; var toScalarType = expectedTypeBase as ScalarType; if (fromScalarType != null && toScalarType != null) { if (ScalarType.IsFloat(fromScalarType) && !ScalarType.IsFloat(toScalarType)) { // Truncation from float to int score += 7; } else if (fromScalarType != toScalarType) { // else different type (implicit cast is usually working) score += 1; } if (!fromScalarType.IsUnsigned && toScalarType.IsUnsigned) { // int to unsigned score += 2; } } // First, try to fix the base type (i.e. the "float" of float3x1) if (argTypeBase != expectedTypeBase && expectedTypeBase is ScalarType) { if (!(argTypeBase is ScalarType)) { score++; // +1 for type conversion } argType = TypeBase.CreateWithBaseType(argType, (ScalarType)expectedTypeBase); } validOverload = TestMethodInvocationArgument(argTypeBase, expectedTypeBase, argType, expectedType, ref score); } } if (validOverload) { overloads.Add( new FunctionOverloadScore { Declaration = methodDeclaration, ParameterTypes = parameterTypes, ReturnType = returnType, Score = score }); } } // In-place sort using List.Sort would be lighter var bestOverload = overloads.OrderBy(x => x.Score).FirstOrDefault(); if (bestOverload != null) { expression.TypeInference.TargetType = bestOverload.ReturnType.ResolveType(); // Override declaration to match exactly the declaration found by method overloaded resolution expression.Target.TypeInference.Declaration = bestOverload.Declaration; // Add appropriate cast for (int i = 0; i < argumentTypes.Length; ++i) { argumentTypeInferences[i].ExpectedType = (bestOverload.ParameterTypes[i] is GenericParameterType) ? argumentTypes[i] : bestOverload.ParameterTypes[i].ResolveType(); } } else { Error(MessageCode.ErrorNoOverloadedMethod, expression.Span, methodName); } }