protected void TypeReferenceInternal(TypeReference tr, TypeReferenceContext context) { var type = TypeUtil.DereferenceType(tr); var typeDef = TypeUtil.GetTypeDefinition(type, false); var typeInfo = TypeInfo.Get(type); var fullName = (typeInfo != null) ? typeInfo.FullName : (typeDef != null) ? typeDef.FullName : type.FullName; AssemblyReference(type); Dot(); WriteRaw("TypeRef"); LPar(); Value(fullName); var git = tr as GenericInstanceType; if (git != null) { EmitGenericTypeReferenceArguments(git, context); } RPar(); }
private bool ShouldExemptVariableFromEffectivelyConstantStatus(string variableName) { // FIXME: Why does this happen? if (!Variables.ContainsKey(variableName)) { return(false); } var actualVariable = Variables[variableName]; var variableType = actualVariable.GetActualType(TypeSystem); // Structs and primitives won't be mutated by functions we pass them to (we ensure this) if (!TypeUtil.IsReferenceType(variableType)) { return(false); } // Strings are immutable. Woot! if (variableType.FullName == "System.String") { return(false); } var variableTypeInfo = TypeInfo.Get(variableType); // The object itself is immutable, so this is probably okay. // FIXME: Transitive modification of the immutable type's members could be a problem here? if ((variableTypeInfo != null) && (variableTypeInfo.IsImmutable)) { return(false); } return(true); }
public void VisitNode(JSDefaultValueLiteral defaultValue) { if (TypeUtil.IsEnum(defaultValue.Value)) { var enumInfo = TypeInfo.Get(defaultValue.Value); if (enumInfo.FirstEnumMember != null) { Output.Identifier(defaultValue.Value, ReferenceContext); Output.Dot(); Output.Identifier(enumInfo.FirstEnumMember.Name); } else { Output.WriteRaw("0"); } } else if (TypeUtil.IsIntegralOrEnum(defaultValue.Value)) { Output.Value(0); } else if (!defaultValue.Value.IsValueType) { Output.WriteRaw("null"); } else { switch (defaultValue.Value.FullName) { case "System.Nullable`1": Output.WriteRaw("null"); break; case "System.Single": case "System.Double": case "System.Decimal": Output.Value(0.0); break; case "System.Char": Output.Value("\0"); break; case "System.Boolean": Output.WriteRaw("false"); break; default: VisitNode(new JSNewExpression(new JSType(defaultValue.Value), null, null)); break; } } }
public void VisitNode(JSCastExpression ce) { var currentType = ce.Expression.GetActualType(TypeSystem); var targetType = ce.NewType; JSExpression newExpression = null; var innerCast = ce.Expression as JSCastExpression; if (targetType.FullName == "System.ValueType") { var replacement = ce.Expression; ParentNode.ReplaceChild(ce, replacement); VisitReplacement(replacement); return; } else if ( TypeUtil.IsIntegralOrEnum(currentType) && (targetType.MetadataType == MetadataType.Char) ) { newExpression = JSInvocationExpression.InvokeStatic( JS.fromCharCode, new[] { ce.Expression }, true ); } else if ( (currentType.MetadataType == MetadataType.Char) && TypeUtil.IsIntegral(targetType) ) { newExpression = JSInvocationExpression.InvokeMethod( JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true ); } else if ( IntroduceEnumCasts.IsEnumOrNullableEnum(currentType) ) { TypeInfo enumInfo; var isNullable = TypeUtil.IsNullable(currentType); if (isNullable) { int temp; var git = (GenericInstanceType)TypeUtil.FullyDereferenceType(currentType, out temp); enumInfo = TypeInfo.Get(git.GenericArguments[0]); } else { enumInfo = TypeInfo.Get(currentType); } if (enumInfo == null) { throw new InvalidOperationException("Unable to extract enum type from typereference " + currentType); } if (targetType.MetadataType == MetadataType.Boolean) { newExpression = new JSBinaryOperatorExpression( JSOperator.NotEqual, JSCastExpression.New(ce.Expression, TypeSystem.Int32, TypeSystem, true, true), new JSIntegerLiteral(0, typeof(Int32)), TypeSystem.Boolean ); } else if (TypeUtil.IsNumeric(targetType)) { if (isNullable) { newExpression = new JSNullableCastExpression(ce.Expression, new JSType(targetType)); } else if ( ce.Expression is JSCastExpression && (((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.Int64 || ((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.UInt64) ) { newExpression = ce.Expression; } else { newExpression = JSInvocationExpression.InvokeMethod( JS.valueOf(targetType), ce.Expression, null, true ); } } else if (targetType.FullName == "System.Enum") { newExpression = ce.Expression; } else { // Debugger.Break(); } } else if ( (targetType.MetadataType == MetadataType.Boolean) && (ce.Expression is JSAsExpression) && ((JSAsExpression)ce.Expression).GetActualType(TypeSystem) is GenericParameter ) { // C# expressions such as (t is T) (where T is a generic parameter). See issue #150. // Tested with AsWithGenericParameter.cs newExpression = new JSBinaryOperatorExpression( JSOperator.NotEqual, ce.Expression, new JSNullLiteral(currentType), TypeSystem.Boolean ); } else if ( (targetType.MetadataType == MetadataType.Boolean) && // A cast from Object to Boolean can occur in two forms: // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc). // In this case, we want to do 'obj != null' to make it a boolean. // An explicit conversion, where an object expression is unboxed to boolean. // In this case we want to leave it as-is. (ce.IsCoercion || (currentType.FullName != "System.Object")) ) { newExpression = new JSBinaryOperatorExpression( JSOperator.NotEqual, ce.Expression, new JSDefaultValueLiteral(currentType), TypeSystem.Boolean ); } else if ( TypeUtil.IsNumeric(targetType) && TypeUtil.IsNumeric(currentType) && !TypeUtil.TypesAreEqual(targetType, currentType, true) ) { TypeReference innerType = null; if (innerCast != null) { innerType = innerCast.Expression.GetActualType(TypeSystem); } if ( TypeUtil.TypesAreAssignable(TypeInfo, targetType, innerType) && ( (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(currentType)) && (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(innerType)) ) && (TypeUtil.IsSigned(targetType) == TypeUtil.IsSigned(innerType)) && (TypeUtil.SizeOfType(targetType) <= TypeUtil.SizeOfType(currentType)) && (TypeUtil.SizeOfType(targetType) >= TypeUtil.SizeOfType(innerType)) ) { // HACK: Turn pointless conversions like '(int32)(int64)(1 + 2)' into '(1 + 2)' newExpression = innerCast.Expression; } else if (currentType.MetadataType == MetadataType.Int64) { if (!EmulateInt64) { newExpression = ce; } else if (targetType.MetadataType == MetadataType.UInt64) { newExpression = JSInvocationExpression .InvokeMethod( TypeSystem.Int64, new JSFakeMethod("ToUInt64", TypeSystem.UInt64, new TypeReference[] { }, MethodTypeFactory), ce.Expression); } else { newExpression = JSInvocationExpression .InvokeMethod( TypeSystem.Int64, new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory), ce.Expression, GetInt64ConversionArgs(targetType)); } } else if (currentType.MetadataType == MetadataType.UInt64) { if (!EmulateInt64) { newExpression = ce; } else if (targetType.MetadataType == MetadataType.Int64) { newExpression = JSInvocationExpression .InvokeMethod( TypeSystem.Int64, new JSFakeMethod("ToInt64", TypeSystem.Int64, new TypeReference[] { }, MethodTypeFactory), ce.Expression); } else { newExpression = JSInvocationExpression .InvokeMethod( TypeSystem.Int64, new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory), ce.Expression, GetInt64ConversionArgs(targetType)); } } else if (targetType.MetadataType == MetadataType.Int64) { if (!EmulateInt64) { newExpression = ce; } else { newExpression = JSInvocationExpression.InvokeStatic( new JSType(TypeSystem.Int64), new JSFakeMethod("FromNumber", TypeSystem.Int64, new[] { currentType }, MethodTypeFactory), new[] { ce.Expression }, true ); } } else if (targetType.MetadataType == MetadataType.UInt64) { if (!EmulateInt64) { newExpression = ce; } else { newExpression = JSInvocationExpression.InvokeStatic( new JSType(TypeSystem.UInt64), new JSFakeMethod("FromNumber", TypeSystem.UInt64, new[] { currentType }, MethodTypeFactory), new[] { ce.Expression }, true ); } } else if (TypeUtil.IsIntegral(currentType)) { if (!TypeUtil.IsIntegral(targetType)) { // Integer -> float conversion newExpression = new JSIntegerToFloatExpression(ce.Expression, targetType); } else if (TypeUtil.SizeOfType(currentType) < TypeUtil.SizeOfType(targetType)) { // Widening integer -> integer conversion newExpression = ce.Expression; } else { newExpression = null; } } else if (TypeUtil.IsIntegral(targetType)) { newExpression = new JSTruncateExpression(ce.Expression); } else if (TypeUtil.SizeOfType(targetType) < TypeUtil.SizeOfType(currentType)) { // Narrowing double -> float conversion newExpression = new JSDoubleToFloatExpression(ce.Expression); } else { // Widening float -> double conversion newExpression = new JSFloatToDoubleExpression(ce.Expression); } } else { // newExpression = JSIL.Cast(ce.Expression, targetType); } if ((newExpression != null) && (newExpression != ce)) { ParentNode.ReplaceChild(ce, newExpression); VisitReplacement(newExpression); } else { // Debugger.Break(); VisitChildren(ce); } }
public void VisitNode(JSCastExpression ce) { var currentType = ce.Expression.GetActualType(TypeSystem); var targetType = ce.NewType; JSExpression newExpression = null; if (targetType.MetadataType == MetadataType.Char) { newExpression = JSInvocationExpression.InvokeStatic( JS.fromCharCode, new[] { ce.Expression }, true ); } else if ( (currentType.MetadataType == MetadataType.Char) && TypeUtil.IsIntegral(targetType) ) { newExpression = JSInvocationExpression.InvokeMethod( JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true ); } else if ( IntroduceEnumCasts.IsEnumOrNullableEnum(currentType) ) { var enumInfo = TypeInfo.Get(currentType); if (targetType.MetadataType == MetadataType.Boolean) { EnumMemberInfo enumMember; if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember)) { newExpression = new JSBinaryOperatorExpression( JSOperator.NotEqual, ce.Expression, new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean ); } else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember)) { newExpression = new JSBinaryOperatorExpression( JSOperator.Equal, ce.Expression, new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean ); } else { newExpression = new JSUntranslatableExpression(String.Format( "Could not cast enum of type '{0}' to boolean because it has no zero value or one value", currentType.FullName )); } } else if (TypeUtil.IsNumeric(targetType)) { newExpression = JSInvocationExpression.InvokeStatic( JS.Number(targetType), new[] { ce.Expression }, true ); } else if (targetType.FullName == "System.Enum") { newExpression = ce.Expression; } else { // Debugger.Break(); } } else if ( targetType.MetadataType == MetadataType.Boolean ) { newExpression = new JSBinaryOperatorExpression( JSBinaryOperator.NotEqual, ce.Expression, new JSDefaultValueLiteral(currentType), TypeSystem.Boolean ); } else if ( TypeUtil.IsNumeric(targetType) && TypeUtil.IsNumeric(currentType) ) { if ( TypeUtil.IsIntegral(currentType) || !TypeUtil.IsIntegral(targetType) ) { newExpression = ce.Expression; } else { newExpression = JSInvocationExpression.InvokeStatic(JS.floor, new[] { ce.Expression }, true); } } else { newExpression = JSIL.Cast(ce.Expression, targetType); } if (newExpression != null) { ParentNode.ReplaceChild(ce, newExpression); VisitReplacement(newExpression); } else { // Debugger.Break(); VisitChildren(ce); } }
public void VisitNode(JSCastExpression ce) { var currentType = ce.Expression.GetActualType(TypeSystem); var targetType = ce.NewType; JSExpression newExpression = null; if (targetType.FullName == "System.ValueType") { var replacement = ce.Expression; ParentNode.ReplaceChild(ce, replacement); VisitReplacement(replacement); return; } else if (targetType.MetadataType == MetadataType.Char) { newExpression = JSInvocationExpression.InvokeStatic( JS.fromCharCode, new[] { ce.Expression }, true ); } else if ( (currentType.MetadataType == MetadataType.Char) && TypeUtil.IsIntegral(targetType) ) { newExpression = JSInvocationExpression.InvokeMethod( JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true ); } else if ( IntroduceEnumCasts.IsEnumOrNullableEnum(currentType) ) { var enumInfo = TypeInfo.Get(currentType); var isNullable = TypeUtil.IsNullable(currentType); if (targetType.MetadataType == MetadataType.Boolean) { EnumMemberInfo enumMember; if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember)) { newExpression = new JSBinaryOperatorExpression( JSOperator.NotEqual, ce.Expression, new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean ); } else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember)) { newExpression = new JSBinaryOperatorExpression( JSOperator.Equal, ce.Expression, new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean ); } else { newExpression = new JSUntranslatableExpression(String.Format( "Could not cast enum of type '{0}' to boolean because it has no zero value or one value", currentType.FullName )); } } else if (TypeUtil.IsNumeric(targetType)) { if (isNullable) { newExpression = JSIL.ValueOfNullable( ce.Expression ); } else { newExpression = JSInvocationExpression.InvokeMethod( JS.valueOf(targetType), ce.Expression, null, true ); } } else if (targetType.FullName == "System.Enum") { newExpression = ce.Expression; } else { // Debugger.Break(); } } else if ( (targetType.MetadataType == MetadataType.Boolean) && // A cast from Object to Boolean can occur in two forms: // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc). // In this case, we want to do 'obj != null' to make it a boolean. // An explicit conversion, where an object expression is unboxed to boolean. // In this case we want to leave it as-is. (ce.IsCoercion || (currentType.FullName != "System.Object")) ) { newExpression = new JSBinaryOperatorExpression( JSBinaryOperator.NotEqual, ce.Expression, new JSDefaultValueLiteral(currentType), TypeSystem.Boolean ); } else if ( TypeUtil.IsNumeric(targetType) && TypeUtil.IsNumeric(currentType) ) { if ( TypeUtil.IsIntegral(currentType) || !TypeUtil.IsIntegral(targetType) ) { newExpression = ce.Expression; } else { newExpression = new JSTruncateExpression(ce.Expression); } } else { // newExpression = JSIL.Cast(ce.Expression, targetType); } if (newExpression != null) { ParentNode.ReplaceChild(ce, newExpression); VisitReplacement(newExpression); } else { // Debugger.Break(); VisitChildren(ce); } }