public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var type = Value.GetClrType(); var method = _systemType.Methods.FirstOrDefault(m => m.Name == "GetTypeFromHandle" && m.Parameters.Count == 1 && m.Parameters[0].Name == "RuntimeTypeHandle"); if (method == null) { throw new XamlIlTypeSystemException( $"Unable to find GetTypeFromHandle(RuntimeTypeHandle) on {_systemType.GetFqn()}"); } codeGen .Emit(OpCodes.Ldtoken, type) .Emit(OpCodes.Call, method); return(XamlIlNodeEmitResult.Type(0, _systemType)); }
private XamlIlNodeEmitResult EmitCore(IXamlIlAstNode value, IXamlIlEmitter codeGen, IXamlIlType expectedType) { CheckingIlEmitter parent = null; CheckingIlEmitter checkedEmitter = null; if (EnableIlVerification) { parent = codeGen as CheckingIlEmitter; parent?.Pause(); checkedEmitter = new CheckingIlEmitter(codeGen); } #if XAMLIL_DEBUG var res = EmitNode(value, checkedEmitter); #else XamlIlNodeEmitResult res; try { res = EmitNode(value, checkedEmitter ?? codeGen); } catch (Exception e) when(!(e is XmlException)) { throw new XamlIlLoadException( "Internal compiler error while emitting node " + value + ":\n" + e, value); } #endif if (EnableIlVerification) { var expectedBalance = res.ProducedItems - res.ConsumedItems; var checkResult = checkedEmitter.Check(res.ProducedItems - res.ConsumedItems, false); if (checkResult != null) { throw new XamlIlLoadException($"Error during IL verification: {checkResult}\n{checkedEmitter}\n", value); } parent?.Resume(); parent?.ExplicitStack(expectedBalance); } var returnedType = res.ReturnType; if (returnedType != null || expectedType != null) { if (returnedType != null && expectedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in {returnedType.GetFqn()} while caller expected void", value); } if (expectedType != null && returnedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in void while caller expected {expectedType.GetFqn()}", value); } if (!returnedType.Equals(expectedType)) { XamlIlLocalsPool.PooledLocal local = null; // ReSharper disable once ExpressionIsAlwaysNull // Value is assigned inside the closure in certain conditions TypeSystemHelpers.EmitConvert(this, value, returnedType, expectedType, ldaddr => { if (ldaddr && returnedType.IsValueType) { // We need to store the value to a temporary variable, since *address* // is required (probably for method call on the value type) local = GetLocal(returnedType); codeGen .Stloc(local.Local) .Ldloca(local.Local); } // Otherwise do nothing, value is already at the top of the stack return(codeGen); }); local?.Dispose(); } } return(res); }
public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what, IXamlIlType to, Func <bool, IXamlIlEmitter> ld) { if (what.Equals(to)) { ld(false); } else if (what == XamlIlPseudoType.Null) { if (to.IsValueType) { if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true) { using (var loc = context.GetLocal(to)) ld(false) .Pop() .Ldloca(loc.Local) .Emit(OpCodes.Initobj, to) .Ldloc(loc.Local); } else { throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node); } } else { ld(false); } } else if (what.IsValueType && to.IsValueType) { if (to.IsNullableOf(what)) { ld(false).Emit(OpCodes.Newobj, to.Constructors.First(c => c.Parameters.Count == 1 && c.Parameters[0].Equals(what))); } else if (what.IsNullableOf(what)) { ld(true) .EmitCall(what.FindMethod(m => m.Name == "get_Value")); } else { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}", node); } } else if (!to.IsValueType && what.IsValueType) { if (!to.IsAssignableFrom(what)) { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}", node); } ld(false).Box(what); } else if (to.IsValueType && !what.IsValueType) { if (!(what.Namespace == "System" && what.Name == "Object")) { throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}", node); } ld(false).Unbox_Any(to); } else { if (to.IsAssignableFrom(what)) { // Downcast, always safe ld(false); } else if (what.IsInterface || what.IsAssignableFrom(to)) { // Upcast or cast from interface, might throw InvalidCastException ld(false).Emit(OpCodes.Castclass, to); } else { // Types are completely unrelated, e. g. string to List<int> conversion attempt throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}", node); } } }
public static IXamlIlMethod GetMethod(this IXamlIlType type, FindMethodMethodSignature signature) { var found = FindMethod(type, signature); if (found == null) { throw new XamlIlTypeSystemException($"Method with signature {signature} is not found on type {type.GetFqn()}"); } return(found); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode value, IXamlIlCodeGen codeGen, IXamlIlType expectedType) { var res = EmitCore(value, codeGen); var returnedType = res.ReturnType; if (returnedType != null || expectedType != null) { if (returnedType != null && expectedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in {returnedType.GetFqn()} while caller expected void", value); } if (expectedType != null && returnedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in void while caller expected {expectedType.GetFqn()}", value); } if (!expectedType.IsAssignableFrom(returnedType)) { throw new XamlIlLoadException( $"Emit of node {value} resulted in {returnedType.GetFqn()} which is not convertible to expected {expectedType.GetFqn()}", value); } if (returnedType.IsValueType && !expectedType.IsValueType) { codeGen.Generator.Emit(OpCodes.Box, returnedType); } } return(res); }
public override string ToString() => Type.GetFqn();