public TranslatedExpression Build(CallInstruction inst) { if (inst is NewObj newobj && IL.Transforms.DelegateConstruction.IsDelegateConstruction(newobj, true)) { return(HandleDelegateConstruction(newobj)); } if (settings.TupleTypes && TupleTransform.MatchTupleConstruction(inst as NewObj, out var tupleElements) && tupleElements.Length >= 2) { var elementTypes = TupleType.GetTupleElementTypes(inst.Method.DeclaringType); Debug.Assert(!elementTypes.IsDefault, "MatchTupleConstruction should not success unless we got a valid tuple type."); Debug.Assert(elementTypes.Length == tupleElements.Length); var tuple = new TupleExpression(); var elementRRs = new List <ResolveResult>(); foreach (var(element, elementType) in tupleElements.Zip(elementTypes)) { var translatedElement = expressionBuilder.Translate(element, elementType) .ConvertTo(elementType, expressionBuilder, allowImplicitConversion: true); tuple.Elements.Add(translatedElement.Expression); elementRRs.Add(translatedElement.ResolveResult); } return(tuple.WithRR(new TupleResolveResult( expressionBuilder.compilation, elementRRs.ToImmutableArray() )).WithILInstruction(inst)); } return(Build(inst.OpCode, inst.Method, inst.Arguments, inst.ConstrainedTo).WithILInstruction(inst)); }
/// <summary> /// Get index of deconstruction result or tuple element /// Returns -1 on failure. /// </summary> int FindIndex(ILInstruction inst, out Action <DeconstructInstruction> delayedActions) { delayedActions = null; if (inst.MatchLdLoc(out var v)) { if (!deconstructionResultsLookup.TryGetValue(v, out int index)) { return(-1); } return(index); } if (inst.MatchLdFld(out _, out _)) { if (!TupleTransform.MatchTupleFieldAccess((LdFlda)((LdObj)inst).Target, out var tupleType, out var target, out int index)) { return(-1); } // Item fields are one-based, we use zero-based indexing. index--; // normalize tuple type tupleType = TupleType.FromUnderlyingType(context.TypeSystem, tupleType); if (!target.MatchLdLoca(out v)) { return(-1); } if (this.tupleVariable == null) { this.tupleVariable = v; this.tupleType = (TupleType)tupleType; this.deconstructionResults = new ILVariable[this.tupleType.Cardinality]; } if (this.tupleType.Cardinality < 2) { return(-1); } if (v != tupleVariable || !this.tupleType.Equals(tupleType)) { return(-1); } if (this.deconstructionResults[index] == null) { var freshVar = new ILVariable(VariableKind.StackSlot, this.tupleType.ElementTypes[index]) { Name = "E_" + index }; delayedActions += _ => context.Function.Variables.Add(freshVar); this.deconstructionResults[index] = freshVar; } delayedActions += _ => { inst.ReplaceWith(new LdLoc(this.deconstructionResults[index])); }; return(index); } return(-1); }