public static IMethod ImplementForwardingCaseFactory(this VirtualType type, string caseName, IMethod caseCtor, IMethod valueTypeCtor) { var valueType = caseCtor.Parameters.Single().Type; Debug.Assert(valueType == valueTypeCtor.DeclaringType); var caseFactory = new VirtualMethod(type, Accessibility.Public, E.SymbolNamer.NameMethod(type, caseName, 0, valueTypeCtor.Parameters, isOverride: false), valueTypeCtor.Parameters, returnType: type, isStatic: true, doccomment: (valueTypeCtor as IWithDoccomment)?.Doccomment ); caseFactory.BodyFactory = () => { var call = new IL.NewObj(valueTypeCtor); call.Arguments.AddRange(valueTypeCtor.Parameters.Select((p, i) => new IL.LdLoc(new IL.ILVariable(IL.VariableKind.Parameter, p.Type, i)))); return(EmitExtensions.CreateExpressionFunction(caseFactory, new IL.NewObj(caseCtor) { Arguments = { call } } )); }; type.Methods.Add(caseFactory); return(caseFactory); }
static IMethod ImplementIntoCaseConversion(this VirtualType type, IType valueType, IMethod caseCtor, bool isImplicit = true) { Debug.Assert(valueType == caseCtor.Parameters.Single().Type); Debug.Assert(valueType.Kind != TypeKind.Interface); // can't have conversion from interface Debug.Assert(valueType != type); // can't have conversion from itself var caseFactory = new VirtualMethod(type, Accessibility.Public, isImplicit ? "op_Implicit" : "op_Explicit", new[] { new VirtualParameter(valueType, "item") }, returnType: type, isStatic: true ); caseFactory.BodyFactory = () => { var @this = new IL.ILVariable(IL.VariableKind.Parameter, valueType, 0); IL.ILInstruction body = new IL.NewObj(caseCtor) { Arguments = { new IL.LdLoc(@this) } }; if (valueType.IsReferenceType == true) { // pass nulls body = new IL.IfInstruction( new IL.Comp(IL.ComparisonKind.Inequality, Sign.None, new IL.LdLoc(@this), new IL.LdNull()), body, new IL.LdNull() ); } return(EmitExtensions.CreateExpressionFunction(caseFactory, body)); }; type.Methods.Add(caseFactory); return(caseFactory); }
public static IL.ILInstruction CreateTuple(ICompilation compilation, params IL.ILInstruction[] nodes) { var restTuple = typeof(ValueTuple <, , , , , , ,>); Debug.Assert(restTuple.GetGenericArguments().Last().Name == "TRest"); var maxSize = restTuple.GetGenericArguments().Length; if (nodes.Length >= maxSize) { return(makeTuple(nodes.Take(maxSize - 1).Append(CreateTuple(compilation, nodes.Skip(maxSize - 1).ToArray())).ToArray())); } else { return(makeTuple(nodes)); } IL.ILInstruction makeTuple(IL.ILInstruction[] n) { var t = //n.Length == 0 ? typeof(ValueTuple) : n.Length == 1 ? typeof(ValueTuple <>) : n.Length == 2 ? typeof(ValueTuple <,>) : n.Length == 3 ? typeof(ValueTuple <, ,>) : n.Length == 4 ? typeof(ValueTuple <, , ,>) : n.Length == 5 ? typeof(ValueTuple <, , , ,>) : n.Length == 6 ? typeof(ValueTuple <, , , , ,>) : n.Length == 7 ? typeof(ValueTuple <, , , , , ,>) : n.Length == 8 ? typeof(ValueTuple <, , , , , , ,>) : throw new NotSupportedException($"ValueTuple can not have {n.Length} parameters"); var tt = new ParameterizedType(compilation.FindType(t), n.Select(a => a.GetObjectResultType())); var ctor = tt.GetConstructors().Single(c => c.Parameters.Count == n.Length); var result = new IL.NewObj(ctor); result.Arguments.AddRange(n); return(result); } }