private static bool TryImplicitConstantConversion(ref BoundExpression boundExpression, TypeSymbol targetType) { if (!boundExpression.IsConstant) { return(false); } if (boundExpression.ValueType == targetType) { return(false); } var targetSystemType = targetType.UdonType.SystemType; object constantValue = boundExpression.ConstantValue.Value; // if (targetSystemType == typeof(string)) // { // IConstantValue constant = new ConstantValue<string>(constantValue?.ToString() ?? ""); // // boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode); // } var sourceSystemType = boundExpression.ValueType.UdonType.SystemType; if (ConstantExpressionOptimizer.CanDoConstantConversion(sourceSystemType) && ConstantExpressionOptimizer.CanDoConstantConversion(targetSystemType)) { IConstantValue constant = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(targetSystemType), ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue)); boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode); return(true); } if (boundExpression.ValueType.IsEnum && boundExpression.ValueType.IsExtern && UdonSharpUtils.IsIntegerType(targetSystemType)) { boundExpression = new BoundConstantExpression(ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue), targetType); return(true); } return(false); }
private void CastValue(Value sourceValue, Value targetValue, bool explicitCast) { if (targetValue.UserType is TypeParameterSymbol) { throw new InvalidOperationException("Target cast type cannot be a generic type parameter"); } if (sourceValue == targetValue) { return; } // Early out for exact type matches if (sourceValue.UserType == targetValue.UserType) { Module.AddCopy(sourceValue, targetValue); return; } TypeSymbol sourceType = sourceValue.UserType; TypeSymbol targetType = targetValue.UserType; void ExecuteBoundInvocation(MethodSymbol conversionMethod) { using (OpenAssignmentScope(targetValue)) { sourceValue = EmitValue(BoundInvocationExpression.CreateBoundInvocation(this, null, conversionMethod, null, new BoundExpression[] { BoundAccessExpression.BindAccess(sourceValue) })); } if (sourceValue != targetValue) { Module.AddCopy(sourceValue, targetValue); } } Conversion conversion = CompileContext.RoslynCompilation.ClassifyConversion(sourceType.RoslynSymbol, targetType.RoslynSymbol); if (conversion.IsEnumeration) { // Extern enum -> integer if (sourceValue.UdonType.IsEnum && UdonSharpUtils.IsIntegerType(targetType.UdonType.SystemType)) { MethodSymbol conversionMethod = GetNumericConversionMethod(GetTypeSymbol(SpecialType.System_Object), targetType); ExecuteBoundInvocation(conversionMethod); return; } // Integer -> user enum // User enum -> user enum if (UdonSharpUtils.IsIntegerType(sourceType.UdonType.SystemType) && !targetType.IsExtern && targetType.IsEnum) { if (sourceType.UdonType == targetType.UdonType) { Module.AddCopy(sourceValue, targetValue); return; } ExecuteBoundInvocation(GetNumericConversionMethod(sourceType.UdonType, targetType.UdonType)); return; } // integer -> extern enum if (UdonSharpUtils.IsIntegerType(sourceType.UdonType.SystemType) && targetType.UdonType.IsEnum) { Value enumArray = GetEnumArrayForType(targetType.UdonType.SystemType); Value indexValue = CastValue(sourceValue, GetTypeSymbol(SpecialType.System_Int32), true); var boundElementAccess = BoundAccessExpression.BindElementAccess(this, null, BoundAccessExpression.BindAccess(enumArray), new BoundExpression[] { BoundAccessExpression.BindAccess(indexValue), }); Value enumVal = EmitValue(boundElementAccess); // todo: get rid of the copy again Module.AddCopy(enumVal, targetValue); return; } } if (conversion.IsNumeric || (UdonSharpUtils.IsNumericType(targetType.UdonType.SystemType) && sourceType == GetTypeSymbol(SpecialType.System_Object))) { MethodSymbol conversionMethod = GetNumericConversionMethod(sourceType, targetType); if (conversionMethod != null) { using (InterruptAssignmentScope()) { // Float to int truncation handling since System.Convert rounds if (UdonSharpUtils.IsFloatType(sourceType.UdonType.SystemType) && UdonSharpUtils.IsIntegerType(targetType.UdonType.SystemType)) { TypeSymbol floatType = GetTypeSymbol(SpecialType.System_Single); sourceValue = CastValue(sourceValue, floatType, true); if (_mathfFloorMethodSymbol == null) { _mathfFloorMethodSymbol = GetTypeSymbol(typeof(Mathf)).GetMember <MethodSymbol>("Floor", this); } sourceValue = EmitValue(BoundInvocationExpression.CreateBoundInvocation(this, null, _mathfFloorMethodSymbol, null, new BoundExpression[] { BoundAccessExpression.BindAccess(sourceValue) })); conversionMethod = GetNumericConversionMethod(floatType, targetType); } } ExecuteBoundInvocation(conversionMethod); return; } } if (conversion.IsUserDefined && conversion.MethodSymbol != null) { MethodSymbol conversionMethod = (MethodSymbol)GetSymbol(conversion.MethodSymbol); ExecuteBoundInvocation(conversionMethod); return; } Module.AddCopy(sourceValue, targetValue); }