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 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);
        }
        public static IMethod ImplementBasicCaseFactory(this VirtualType type, string caseName, IMethod caseCtor)
        {
            var valueType   = caseCtor.Parameters.Single().Type;
            var doccomment  = (valueType.GetDefinition() as IWithDoccomment)?.Doccomment;
            var caseFactory = new VirtualMethod(type, Accessibility.Public,
                                                E.SymbolNamer.NameMethod(type, caseName, 0, new [] { valueType }, isOverride: false),
                                                new[] { new VirtualParameter(valueType, "item") },
                                                returnType: type,
                                                isStatic: true,
                                                doccomment: doccomment
                                                );

            caseFactory.BodyFactory = () =>
                                      EmitExtensions.CreateExpressionFunction(caseFactory,
                                                                              new IL.NewObj(caseCtor)
            {
                Arguments = { new IL.LdLoc(new IL.ILVariable(IL.VariableKind.Parameter, valueType, 0)) }
            }
                                                                              );
            type.Methods.Add(caseFactory);
            return(caseFactory);
        }