internal override IEnumerable <Instruction> Compile() { // First, create all the temporary variables we need // in order to compute List <Instruction> instructions = new List <Instruction>(); RedwoodType[] argumentTypes = new RedwoodType[Arguments.Length]; int[] argumentLocations = new int[Arguments.Length]; for (int i = 0; i < Arguments.Length; i++) { argumentTypes[i] = Arguments[i].GetKnownType(); argumentLocations[i] = ArgumentVariables[i].Location; instructions.AddRange(Arguments[i].Compile()); // Make sure that argument is coerced to the correct type before // we send it off, but make sure not to do it when the callee // is vague about the type, or we're still not fully resolved // (in which case the TryCallInstruction should ideally handle conversion) if (FullyResolved && LambdaType?.GenericArguments != null && LambdaType.GenericArguments.Length != 0 && LambdaType.GenericArguments[i] != null) { instructions.AddRange( Compiler.CompileImplicitConversion( argumentTypes[i], LambdaType.GenericArguments[i] ) ); } instructions.Add(Compiler.CompileVariableAssign(ArgumentVariables[i])); } if (Callee == null) { instructions.AddRange(FunctionName.Compile()); // TODO: Should this just use LambdaType? RedwoodType knownType = FunctionName.GetKnownType(); CompileCallNoCallee(instructions, argumentTypes, argumentLocations, knownType); } else { RedwoodType calleeType = Callee.GetKnownType(); // Calls that are not fully resolved MUST rely on some amount of // dynamic resolution if (calleeType == null || !FullyResolved) { instructions.AddRange(Callee.Compile()); // Try to resolve on the fly if we can't figure it out instructions.Add(new LookupExternalMemberLambdaInstruction(FunctionName.Name, calleeType)); instructions.Add(new TryCallInstruction(argumentTypes, argumentLocations)); } else if (calleeType.CSharpType == null) { instructions.AddRange(Callee.Compile()); instructions.Add( new LookupDirectMemberInstruction( calleeType.GetSlotNumberForOverload(FunctionName.Name, argumentTypes))); instructions.Add(new InternalCallInstruction(argumentLocations)); } else if (calleeType.CSharpType == typeof(RedwoodType)) { if (!Callee.Constant) { instructions.AddRange(Callee.Compile()); instructions.Add(new TryCallInstruction( FunctionName.Name, calleeType, argumentTypes, argumentLocations) ); } else if (Callee.EvaluateConstant() is RedwoodType type) { if (type.CSharpType == null) { int index = type.staticSlotMap[FunctionName.Name]; instructions.Add(new LookupDirectStaticMemberInstruction(type, index)); // Since this is a static member on the class and may be an // overload, let's defer to our logic for a simple calls. CompileCallNoCallee( instructions, argumentTypes, argumentLocations, type.staticSlotTypes[index] ); } else { instructions.Add(new LoadConstantInstruction(null)); instructions.Add(new BuildExternalLambdaInstruction(ExternalMethodGroup)); instructions.Add(new ExternalCallInstruction(argumentLocations)); } } else { throw new NotImplementedException(); } } else { instructions.AddRange(Callee.Compile()); instructions.Add(new BuildExternalLambdaInstruction(ExternalMethodGroup)); instructions.Add(new ExternalCallInstruction(argumentLocations)); } } return(instructions); }