<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />

ExpressionBinder

using Microsoft.CSharp.RuntimeBinder.Errors; using Microsoft.CSharp.RuntimeBinder.Syntax; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; namespace Microsoft.CSharp.RuntimeBinder.Semantics { internal readonly struct ExpressionBinder { private sealed class BinOpArgInfo { public Expr arg1; public Expr arg2; public PredefinedType pt1; public PredefinedType pt2; public PredefinedType ptRaw1; public PredefinedType ptRaw2; public CType type1; public CType type2; public CType typeRaw1; public CType typeRaw2; public BinOpKind binopKind; public BinOpMask mask; public BinOpArgInfo(Expr op1, Expr op2) { arg1 = op1; arg2 = op2; type1 = arg1.Type; type2 = arg2.Type; typeRaw1 = type1.StripNubs(); typeRaw2 = type2.StripNubs(); pt1 = (type1.IsPredefined ? type1.PredefinedType : PredefinedType.PT_COUNT); pt2 = (type2.IsPredefined ? type2.PredefinedType : PredefinedType.PT_COUNT); ptRaw1 = (typeRaw1.IsPredefined ? typeRaw1.PredefinedType : PredefinedType.PT_COUNT); ptRaw2 = (typeRaw2.IsPredefined ? typeRaw2.PredefinedType : PredefinedType.PT_COUNT); } public bool ValidForDelegate() { return (mask & BinOpMask.Delegate) != BinOpMask.None; } public bool ValidForEnumAndUnderlyingType() { return (mask & BinOpMask.EnumUnder) != BinOpMask.None; } public bool ValidForUnderlyingTypeAndEnum() { return (mask & BinOpMask.Add) != BinOpMask.None; } public bool ValidForEnum() { return (mask & BinOpMask.Enum) != BinOpMask.None; } } private class BinOpSig { public PredefinedType pt1; public PredefinedType pt2; public BinOpMask mask; public int cbosSkip; public PfnBindBinOp pfn; public OpSigFlags grfos; public BinOpFuncKind fnkind; protected BinOpSig() { } public BinOpSig(PredefinedType pt1, PredefinedType pt2, BinOpMask mask, int cbosSkip, PfnBindBinOp pfn, OpSigFlags grfos, BinOpFuncKind fnkind) { this.pt1 = pt1; this.pt2 = pt2; this.mask = mask; this.cbosSkip = cbosSkip; this.pfn = pfn; this.grfos = grfos; this.fnkind = fnkind; } public bool ConvertOperandsBeforeBinding() { return (grfos & OpSigFlags.Convert) != OpSigFlags.None; } public bool CanLift() { return (grfos & OpSigFlags.CanLift) != OpSigFlags.None; } public bool AutoLift() { return (grfos & OpSigFlags.AutoLift) != OpSigFlags.None; } } private sealed class BinOpFullSig : BinOpSig { private readonly LiftFlags _grflt; private readonly CType _type1; private readonly CType _type2; public BinOpFullSig(CType type1, CType type2, PfnBindBinOp pfn, OpSigFlags grfos, LiftFlags grflt, BinOpFuncKind fnkind) { pt1 = PredefinedType.PT_UNDEFINEDINDEX; pt2 = PredefinedType.PT_UNDEFINEDINDEX; mask = BinOpMask.None; cbosSkip = 0; base.pfn = pfn; base.grfos = grfos; _type1 = type1; _type2 = type2; _grflt = grflt; base.fnkind = fnkind; } public BinOpFullSig(ExpressionBinder fnc, BinOpSig bos) { pt1 = bos.pt1; pt2 = bos.pt2; mask = bos.mask; cbosSkip = bos.cbosSkip; pfn = bos.pfn; grfos = bos.grfos; fnkind = bos.fnkind; _type1 = ((pt1 != PredefinedType.PT_UNDEFINEDINDEX) ? GetPredefindType(pt1) : null); _type2 = ((pt2 != PredefinedType.PT_UNDEFINEDINDEX) ? GetPredefindType(pt2) : null); _grflt = LiftFlags.None; } public bool FPreDef() { return pt1 != PredefinedType.PT_UNDEFINEDINDEX; } public bool isLifted() { if (_grflt == LiftFlags.None) return false; return true; } public bool ConvertFirst() { return (_grflt & LiftFlags.Convert1) != LiftFlags.None; } public bool ConvertSecond() { return (_grflt & LiftFlags.Convert2) != LiftFlags.None; } public CType Type1() { return _type1; } public CType Type2() { return _type2; } } private delegate bool ConversionFunc (Expr pSourceExpr, CType pSourceType, CType pDestinationType, bool needsExprDest, out Expr ppDestinationExpr, CONVERTTYPE flags); private sealed class ExplicitConversion { private readonly ExpressionBinder _binder; private Expr _exprSrc; private readonly CType _typeSrc; private readonly CType _typeDest; private Expr _exprDest; private readonly bool _needsExprDest; private readonly CONVERTTYPE _flags; public Expr ExprDest => _exprDest; public ExplicitConversion(ExpressionBinder binder, Expr exprSrc, CType typeSrc, CType typeDest, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; } public bool Bind() { if (_binder.BindImplicitConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.ISEXPLICIT)) return true; if (_typeSrc == null || _typeDest == null || _typeDest is MethodGroupType) return false; if (_typeDest is NullableType) return false; if (_typeSrc is NullableType) return bindExplicitConversionFromNub(); if (bindExplicitConversionFromArrayToIList()) return true; switch (_typeDest.TypeKind) { default: return false; case TypeKind.TK_VoidType: return false; case TypeKind.TK_NullType: return false; case TypeKind.TK_ArrayType: if (bindExplicitConversionToArray((ArrayType)_typeDest)) return true; break; case TypeKind.TK_PointerType: if (bindExplicitConversionToPointer()) return true; break; case TypeKind.TK_AggregateType: switch (bindExplicitConversionToAggregate(_typeDest as AggregateType)) { case AggCastResult.Success: return true; case AggCastResult.Abort: return false; } break; } if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false); return false; } private bool bindExplicitConversionFromNub() { if (_typeDest.IsValueType && _binder.BindExplicitConversion(null, _typeSrc.StripNubs(), _typeDest, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { Expr expr = _exprSrc; if (expr.Type is NullableType) expr = BindNubValue(expr); if (!_binder.BindExplicitConversion(expr, expr.Type, _typeDest, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.NOUDC)) return false; ExprUserDefinedConversion exprUserDefinedConversion = _exprDest as ExprUserDefinedConversion; if (exprUserDefinedConversion != null) exprUserDefinedConversion.Argument = _exprSrc; } return true; } if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false); return false; } private bool bindExplicitConversionFromArrayToIList() { ArrayType arrayType = _typeSrc as ArrayType; if (arrayType != null && arrayType.IsSZArray) { AggregateType aggregateType = _typeDest as AggregateType; if (aggregateType != null && aggregateType.IsInterfaceType && aggregateType.TypeArgsAll.Count == 1) { AggregateSymbol predefAgg = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol predefAgg2 = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((predefAgg == null || !SymbolLoader.IsBaseAggregate(predefAgg, aggregateType.OwningAggregate)) && (predefAgg2 == null || !SymbolLoader.IsBaseAggregate(predefAgg2, aggregateType.OwningAggregate))) return false; CType elementType = arrayType.ElementType; CType typeDst = aggregateType.TypeArgsAll[0]; if (!CConversions.FExpRefConv(elementType, typeDst)) return false; if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_OPERATOR); return true; } } return false; } private bool bindExplicitConversionFromIListToArray(ArrayType arrayDest) { if (arrayDest.IsSZArray) { AggregateType aggregateType = _typeSrc as AggregateType; if (aggregateType != null && aggregateType.IsInterfaceType && aggregateType.TypeArgsAll.Count == 1) { AggregateSymbol predefAgg = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol predefAgg2 = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((predefAgg == null || !SymbolLoader.IsBaseAggregate(predefAgg, aggregateType.OwningAggregate)) && (predefAgg2 == null || !SymbolLoader.IsBaseAggregate(predefAgg2, aggregateType.OwningAggregate))) return false; CType elementType = arrayDest.ElementType; CType cType = aggregateType.TypeArgsAll[0]; if (elementType != cType && !CConversions.FExpRefConv(elementType, cType)) return false; if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_OPERATOR); return true; } } return false; } private bool bindExplicitConversionFromArrayToArray(ArrayType arraySrc, ArrayType arrayDest) { if (arraySrc.Rank != arrayDest.Rank || arraySrc.IsSZArray != arrayDest.IsSZArray) return false; if (CConversions.FExpRefConv(arraySrc.ElementType, arrayDest.ElementType)) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_OPERATOR); return true; } return false; } private bool bindExplicitConversionToArray(ArrayType arrayDest) { ArrayType arrayType = _typeSrc as ArrayType; if (arrayType != null) return bindExplicitConversionFromArrayToArray(arrayType, arrayDest); if (bindExplicitConversionFromIListToArray(arrayDest)) return true; if (_binder.canConvert(GetPredefindType(PredefinedType.PT_ARRAY), _typeSrc, CONVERTTYPE.NOUDC)) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_OPERATOR); return true; } return false; } private bool bindExplicitConversionToPointer() { if (_typeSrc is PointerType || (_typeSrc.FundamentalType <= FUNDTYPE.FT_U8 && _typeSrc.IsNumericType)) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return true; } return false; } private AggCastResult bindExplicitConversionFromEnumToAggregate(AggregateType aggTypeDest) { if (!_typeSrc.IsEnumType) return AggCastResult.Failure; AggregateSymbol owningAggregate = aggTypeDest.OwningAggregate; if (owningAggregate.isPredefAgg(PredefinedType.PT_DECIMAL)) return bindExplicitConversionFromEnumToDecimal(aggTypeDest); if (!owningAggregate.getThisType().IsNumericType && !owningAggregate.IsEnum() && (!owningAggregate.IsPredefined() || owningAggregate.GetPredefType() != PredefinedType.PT_CHAR)) return AggCastResult.Failure; if (_exprSrc.GetConst() != null) { switch (_binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, true)) { case ConstCastResult.Success: return AggCastResult.Success; case ConstCastResult.CheckFailure: return AggCastResult.Abort; } } if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return AggCastResult.Success; } private AggCastResult bindExplicitConversionFromDecimalToEnum(AggregateType aggTypeDest) { if (_exprSrc.GetConst() != null) { switch (_binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, true)) { case ConstCastResult.Success: return AggCastResult.Success; case ConstCastResult.CheckFailure: if ((_flags & CONVERTTYPE.CHECKOVERFLOW) == (CONVERTTYPE)0) return AggCastResult.Abort; break; } } bool flag = true; if (_needsExprDest) { CType underlyingEnumType = aggTypeDest.UnderlyingEnumType; flag = _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, underlyingEnumType, _needsExprDest, out _exprDest, false); if (flag) _binder.bindSimpleCast(_exprDest, _typeDest, out _exprDest); } if (!flag) return AggCastResult.Failure; return AggCastResult.Success; } private AggCastResult bindExplicitConversionFromEnumToDecimal(AggregateType aggTypeDest) { AggregateType underlyingEnumType = _typeSrc.UnderlyingEnumType; Expr pexprDest; if (_exprSrc == null) pexprDest = null; else _binder.bindSimpleCast(_exprSrc, underlyingEnumType, out pexprDest); if (pexprDest.GetConst() != null) { switch (_binder.bindConstantCast(pexprDest, _typeDest, _needsExprDest, out _exprDest, true)) { case ConstCastResult.Success: return AggCastResult.Success; case ConstCastResult.CheckFailure: if ((_flags & CONVERTTYPE.CHECKOVERFLOW) == (CONVERTTYPE)0) return AggCastResult.Abort; break; } } if (_needsExprDest) { bool flag = _binder.bindUserDefinedConversion(pexprDest, underlyingEnumType, aggTypeDest, _needsExprDest, out _exprDest, false); } return AggCastResult.Success; } private AggCastResult bindExplicitConversionToEnum(AggregateType aggTypeDest) { AggregateSymbol owningAggregate = aggTypeDest.OwningAggregate; if (!owningAggregate.IsEnum()) return AggCastResult.Failure; if (_typeSrc.IsPredefType(PredefinedType.PT_DECIMAL)) return bindExplicitConversionFromDecimalToEnum(aggTypeDest); if (_typeSrc.IsNumericType || (_typeSrc.IsPredefined && _typeSrc.PredefinedType == PredefinedType.PT_CHAR)) { if (_exprSrc.GetConst() != null) { switch (_binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, true)) { case ConstCastResult.Success: return AggCastResult.Success; case ConstCastResult.CheckFailure: return AggCastResult.Abort; } } if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return AggCastResult.Success; } if (_typeSrc.IsPredefined && (_typeSrc.IsPredefType(PredefinedType.PT_OBJECT) || _typeSrc.IsPredefType(PredefinedType.PT_VALUE) || _typeSrc.IsPredefType(PredefinedType.PT_ENUM))) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_INDEXER); return AggCastResult.Success; } return AggCastResult.Failure; } private AggCastResult bindExplicitConversionBetweenSimpleTypes(AggregateType aggTypeDest) { if (!_typeSrc.IsSimpleType || !aggTypeDest.IsSimpleType) return AggCastResult.Failure; AggregateSymbol owningAggregate = aggTypeDest.OwningAggregate; PredefinedType predefinedType = _typeSrc.PredefinedType; PredefinedType predefType = owningAggregate.GetPredefType(); ConvKind convKind = GetConvKind(predefinedType, predefType); if (convKind != ConvKind.Explicit) return AggCastResult.Failure; if (_exprSrc.GetConst() != null) { switch (_binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, true)) { case ConstCastResult.Success: return AggCastResult.Success; case ConstCastResult.CheckFailure: if ((_flags & CONVERTTYPE.CHECKOVERFLOW) == (CONVERTTYPE)0) return AggCastResult.Abort; break; } } bool flag = true; if (_needsExprDest) { if (isUserDefinedConversion(predefinedType, predefType)) flag = _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, aggTypeDest, _needsExprDest, out _exprDest, false); else _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, ((_flags & CONVERTTYPE.CHECKOVERFLOW) != 0) ? EXPRFLAG.EXF_CHECKOVERFLOW : ((EXPRFLAG)0)); } if (!flag) return AggCastResult.Failure; return AggCastResult.Success; } private AggCastResult bindExplicitConversionBetweenAggregates(AggregateType aggTypeDest) { AggregateType aggregateType = _typeSrc as AggregateType; if (aggregateType == null) return AggCastResult.Failure; AggregateSymbol owningAggregate = aggregateType.OwningAggregate; AggregateSymbol owningAggregate2 = aggTypeDest.OwningAggregate; if (SymbolLoader.HasBaseConversion(aggTypeDest, aggregateType)) { if (_needsExprDest) { ref ExpressionBinder binder = ref _binder; Expr exprSrc = _exprSrc; CType typeDest = _typeDest; ref Expr exprDest = ref _exprDest; int exprFlags; if (!owningAggregate2.IsValueType() || owningAggregate.getThisType().FundamentalType != FUNDTYPE.FT_REF) { Expr exprSrc2 = _exprSrc; exprFlags = (int)(EXPRFLAG.EXF_OPERATOR | ((exprSrc2 != null) ? (exprSrc2.Flags & EXPRFLAG.EXF_CANTBENULL) : ((EXPRFLAG)0))); } else exprFlags = 4; binder.bindSimpleCast(exprSrc, typeDest, out exprDest, (EXPRFLAG)exprFlags); } return AggCastResult.Success; } if ((owningAggregate.IsClass() && !owningAggregate.IsSealed() && owningAggregate2.IsInterface()) || (owningAggregate.IsInterface() && owningAggregate2.IsClass() && !owningAggregate2.IsSealed()) || (owningAggregate.IsInterface() && owningAggregate2.IsInterface()) || CConversions.HasGenericDelegateExplicitReferenceConversion(_typeSrc, aggTypeDest)) { if (_needsExprDest) { ref ExpressionBinder binder2 = ref _binder; Expr exprSrc3 = _exprSrc; CType typeDest2 = _typeDest; ref Expr exprDest2 = ref _exprDest; Expr exprSrc4 = _exprSrc; binder2.bindSimpleCast(exprSrc3, typeDest2, out exprDest2, EXPRFLAG.EXF_OPERATOR | ((exprSrc4 != null) ? (exprSrc4.Flags & EXPRFLAG.EXF_CANTBENULL) : ((EXPRFLAG)0))); } return AggCastResult.Success; } return AggCastResult.Failure; } private AggCastResult bindExplicitConversionFromPointerToInt(AggregateType aggTypeDest) { if (!(_typeSrc is PointerType) || aggTypeDest.FundamentalType > FUNDTYPE.FT_U8 || !aggTypeDest.IsNumericType) return AggCastResult.Failure; if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return AggCastResult.Success; } private AggCastResult bindExplicitConversionToAggregate(AggregateType aggTypeDest) { AggCastResult aggCastResult = bindExplicitConversionFromEnumToAggregate(aggTypeDest); if (aggCastResult != AggCastResult.Failure) return aggCastResult; aggCastResult = bindExplicitConversionToEnum(aggTypeDest); if (aggCastResult != AggCastResult.Failure) return aggCastResult; aggCastResult = bindExplicitConversionBetweenSimpleTypes(aggTypeDest); if (aggCastResult != AggCastResult.Failure) return aggCastResult; aggCastResult = bindExplicitConversionBetweenAggregates(aggTypeDest); if (aggCastResult != AggCastResult.Failure) return aggCastResult; aggCastResult = bindExplicitConversionFromPointerToInt(aggTypeDest); if (aggCastResult != AggCastResult.Failure) return aggCastResult; if (_typeSrc is VoidType) return AggCastResult.Abort; return AggCastResult.Failure; } } private delegate Expr PfnBindBinOp (ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr op1, Expr op2); private delegate Expr PfnBindUnaOp (ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr op); public enum NamedArgumentsKind { None, Positioning, NonTrailing } internal sealed class GroupToArgsBinder { private enum Result { Success, Failure_SearchForExpanded, Failure_NoSearchForExpanded } private readonly ExpressionBinder _pExprBinder; private bool _fCandidatesUnsupported; private readonly BindingFlag _fBindFlags; private readonly ExprMemberGroup _pGroup; private readonly ArgInfos _pArguments; private readonly ArgInfos _pOriginalArguments; private readonly NamedArgumentsKind _namedArgumentsKind; private AggregateType _pCurrentType; private MethodOrPropertySymbol _pCurrentSym; private TypeArray _pCurrentTypeArgs; private TypeArray _pCurrentParameters; private int _nArgBest; private readonly GroupToArgsBinderResult _results; private readonly List<CandidateFunctionMember> _methList; private readonly MethPropWithInst _mpwiParamTypeConstraints; private readonly MethPropWithInst _mpwiBogus; private readonly MethPropWithInst _misnamed; private readonly MethPropWithInst _mpwiCantInferInstArg; private readonly MethWithType _mwtBadArity; private Name _pInvalidSpecifiedName; private Name _pNameUsedInPositionalArgument; private Name _pDuplicateSpecifiedName; private readonly List<CType> _HiddenTypes; private bool _bArgumentsChangedForNamedOrOptionalArguments; public GroupToArgsBinder(ExpressionBinder exprBinder, BindingFlag bindFlags, ExprMemberGroup grp, ArgInfos args, ArgInfos originalArgs, NamedArgumentsKind namedArgumentsKind) { _pExprBinder = exprBinder; _fCandidatesUnsupported = false; _fBindFlags = bindFlags; _pGroup = grp; _pArguments = args; _pOriginalArguments = originalArgs; _namedArgumentsKind = namedArgumentsKind; _pCurrentType = null; _pCurrentSym = null; _pCurrentTypeArgs = null; _pCurrentParameters = null; _nArgBest = -1; _results = new GroupToArgsBinderResult(); _methList = new List<CandidateFunctionMember>(); _mpwiParamTypeConstraints = new MethPropWithInst(); _mpwiBogus = new MethPropWithInst(); _misnamed = new MethPropWithInst(); _mpwiCantInferInstArg = new MethPropWithInst(); _mwtBadArity = new MethWithType(); _HiddenTypes = new List<CType>(); } public void Bind() { LookForCandidates(); if (!GetResultOfBind()) throw ReportErrorsOnFailure(); } public GroupToArgsBinderResult GetResultsOfBind() { return _results; } private static CType GetTypeQualifier(ExprMemberGroup pGroup) { if ((pGroup.Flags & EXPRFLAG.EXF_CTOR) == (EXPRFLAG)0) return pGroup.OptionalObject?.Type; return pGroup.ParentType; } private void LookForCandidates() { bool flag = false; bool flag2 = true; bool flag3 = true; bool flag4 = false; symbmask_t mask = (symbmask_t)(1 << (int)_pGroup.SymKind); CMemberLookupResults.CMethodIterator methodIterator = _pGroup.MemberLookupResults.GetMethodIterator(GetTypeQualifier(_pGroup), _pExprBinder.ContextForMemberLookup, _pGroup.TypeArgs.Count, _pGroup.Flags, mask, (_namedArgumentsKind == NamedArgumentsKind.NonTrailing) ? _pOriginalArguments : null); while (true) { bool flag5 = false; if (flag2 && !flag) flag5 = (flag = ConstructExpandedParameters()); if (!flag5) { flag = false; if (!GetNextSym(methodIterator)) break; _pCurrentParameters = _pCurrentSym.Params; flag2 = true; } if (_bArgumentsChangedForNamedOrOptionalArguments) { _bArgumentsChangedForNamedOrOptionalArguments = false; CopyArgInfos(_pOriginalArguments, _pArguments); } if (_namedArgumentsKind == NamedArgumentsKind.Positioning) { if (!ReOrderArgsForNamedArguments()) continue; } else if (HasOptionalParameters() && !AddArgumentsForOptionalParameters()) { continue; } if (!flag5) { flag4 = true; flag3 &= CSemanticChecker.CheckBogus(_pCurrentSym); if (_pCurrentParameters.Count != _pArguments.carg) { flag2 = true; continue; } } if (methodIterator.CanUseCurrentSymbol) { Result result = DetermineCurrentTypeArgs(); if (result != 0) flag2 = (result == Result.Failure_SearchForExpanded); else { bool flag6 = !methodIterator.IsCurrentSymbolInaccessible; if (!flag6 && (!_methList.IsEmpty() || (bool)_results.InaccessibleResult)) flag2 = false; else { bool flag7 = flag6 && methodIterator.IsCurrentSymbolMisnamed; if (flag7 && (!_methList.IsEmpty() || (bool)_results.InaccessibleResult || (bool)_misnamed)) flag2 = false; else { bool flag8 = flag6 && !flag7 && methodIterator.IsCurrentSymbolBogus; if (flag8 && (!_methList.IsEmpty() || (bool)_results.InaccessibleResult || (bool)_mpwiBogus || (bool)_misnamed)) flag2 = false; else if (!ArgumentsAreConvertible()) { flag2 = true; } else { if (!flag6) _results.InaccessibleResult.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); else if (flag7) { _misnamed.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); } else if (flag8) { _mpwiBogus.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); } else { _methList.Add(new CandidateFunctionMember(new MethPropWithInst(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs), _pCurrentParameters, 0, flag)); if (_pCurrentType.IsInterfaceType) { CType[] items = _pCurrentType.IfacesAll.Items; for (int i = 0; i < items.Length; i++) { AggregateType item = (AggregateType)items[i]; _HiddenTypes.Add(item); } AggregateType predefindType = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT); _HiddenTypes.Add(predefindType); } } flag2 = false; } } } } } } _fCandidatesUnsupported = (flag3 & flag4); if (_bArgumentsChangedForNamedOrOptionalArguments) CopyArgInfos(_pOriginalArguments, _pArguments); } private static void CopyArgInfos(ArgInfos src, ArgInfos dst) { dst.carg = src.carg; dst.types = src.types; dst.prgexpr.Clear(); for (int i = 0; i < src.prgexpr.Count; i++) { dst.prgexpr.Add(src.prgexpr[i]); } } private bool GetResultOfBind() { if (!_methList.IsEmpty()) { CandidateFunctionMember candidateFunctionMember; if (_methList.Count == 1) candidateFunctionMember = _methList.Head(); else { CType pTypeThrough = _pGroup.OptionalObject?.Type; candidateFunctionMember = _pExprBinder.FindBestMethod(_methList, pTypeThrough, _pArguments, out CandidateFunctionMember methAmbig, out CandidateFunctionMember methAmbig2); if (candidateFunctionMember == null) { if (methAmbig.params != methAmbig2.params || methAmbig.mpwi.MethProp().Params.Count != methAmbig2.mpwi.MethProp().Params.Count || methAmbig.mpwi.TypeArgs != methAmbig2.mpwi.TypeArgs || methAmbig.mpwi.GetType() != methAmbig2.mpwi.GetType() || methAmbig.mpwi.MethProp().Params == methAmbig2.mpwi.MethProp().Params) throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, methAmbig.mpwi, methAmbig2.mpwi); throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, methAmbig.mpwi.MethProp(), methAmbig2.mpwi.MethProp()); } } _results.BestResult = candidateFunctionMember.mpwi; ReportErrorsOnSuccess(); return true; } return false; } private bool ReOrderArgsForNamedArguments() { MethodOrPropertySymbol methodOrPropertySymbol = FindMostDerivedMethod(_pCurrentSym, _pGroup.OptionalObject); if (methodOrPropertySymbol == null) return false; int count = _pCurrentParameters.Count; if (count == 0 || count < _pArguments.carg) return false; if (!NamedArgumentNamesAppearInParameterList(methodOrPropertySymbol)) return false; _bArgumentsChangedForNamedOrOptionalArguments = ReOrderArgsForNamedArguments(methodOrPropertySymbol, _pCurrentParameters, _pCurrentType, _pGroup, _pArguments); return _bArgumentsChangedForNamedOrOptionalArguments; } internal static bool ReOrderArgsForNamedArguments(MethodOrPropertySymbol methprop, TypeArray pCurrentParameters, AggregateType pCurrentType, ExprMemberGroup pGroup, ArgInfos pArguments) { int count = pCurrentParameters.Count; Expr[] array = new Expr[count]; int num = 0; Expr expr = null; TypeArray typeArray = TypeManager.SubstTypeArray(pCurrentParameters, pCurrentType, pGroup.TypeArgs); foreach (Name parameterName in methprop.ParameterNames) { if (num >= pCurrentParameters.Count) break; if (methprop.isParamArray && num < pArguments.carg) { ExprArrayInit exprArrayInit = pArguments.prgexpr[num] as ExprArrayInit; if (exprArrayInit != null && exprArrayInit.GeneratedForParamArray) expr = pArguments.prgexpr[num]; } if (num < pArguments.carg && !(pArguments.prgexpr[num] is ExprNamedArgumentSpecification)) { ExprArrayInit exprArrayInit2 = pArguments.prgexpr[num] as ExprArrayInit; if (exprArrayInit2 == null || !exprArrayInit2.GeneratedForParamArray) { array[num] = pArguments.prgexpr[num++]; continue; } } Expr expr2 = FindArgumentWithName(pArguments, parameterName); if (expr2 == null) { if (methprop.IsParameterOptional(num)) expr2 = GenerateOptionalArgument(methprop, typeArray[num], num); else { if (expr == null || num != methprop.Params.Count - 1) return false; expr2 = expr; } } array[num++] = expr2; } CType[] array2 = new CType[pCurrentParameters.Count]; for (int i = 0; i < count; i++) { if (i < pArguments.prgexpr.Count) pArguments.prgexpr[i] = array[i]; else pArguments.prgexpr.Add(array[i]); array2[i] = pArguments.prgexpr[i].Type; } pArguments.carg = pCurrentParameters.Count; pArguments.types = TypeArray.Allocate(array2); return true; } private static Expr GenerateOptionalArgument(MethodOrPropertySymbol methprop, CType type, int index) { CType cType = type.StripNubs(); Expr expr; if (methprop.HasDefaultParameterValue(index)) { CType defaultParameterValueConstValType = methprop.GetDefaultParameterValueConstValType(index); ConstVal defaultParameterValue = methprop.GetDefaultParameterValue(index); if (!defaultParameterValueConstValType.IsPredefType(PredefinedType.PT_DATETIME) || (!cType.IsPredefType(PredefinedType.PT_DATETIME) && !cType.IsPredefType(PredefinedType.PT_OBJECT) && !cType.IsPredefType(PredefinedType.PT_VALUE))) expr = (defaultParameterValueConstValType.IsSimpleOrEnumOrString ? ExprFactory.CreateConstant((cType.IsEnumType && defaultParameterValueConstValType == cType.UnderlyingEnumType) ? cType : defaultParameterValueConstValType, defaultParameterValue) : (((!type.IsReferenceType && !(type is NullableType)) || !defaultParameterValue.IsNullRef) ? ExprFactory.CreateZeroInit(type) : ExprFactory.CreateNull())); else { AggregateType predefindType = SymbolLoader.GetPredefindType(PredefinedType.PT_DATETIME); expr = ExprFactory.CreateConstant(predefindType, ConstVal.Get(DateTime.FromBinary(defaultParameterValue.Int64Val))); } } else if (type.IsPredefType(PredefinedType.PT_OBJECT)) { if (methprop.MarshalAsObject(index)) expr = ExprFactory.CreateNull(); else { AggregateSymbol predefAgg = SymbolLoader.GetPredefAgg(PredefinedType.PT_MISSING); Name predefinedName = NameManager.GetPredefinedName(PredefinedName.PN_CAP_VALUE); FieldSymbol field = SymbolLoader.LookupAggMember(predefinedName, predefAgg, symbmask_t.MASK_FieldSymbol) as FieldSymbol; FieldWithType field2 = new FieldWithType(field, predefAgg.getThisType()); ExprField argument = ExprFactory.CreateField(predefAgg.getThisType(), null, field2); expr = ExprFactory.CreateCast(type, argument); } } else { expr = ExprFactory.CreateZeroInit(type); } expr.IsOptionalArgument = true; return expr; } private static MethodOrPropertySymbol FindMostDerivedMethod(MethodOrPropertySymbol pMethProp, Expr pObject) { return FindMostDerivedMethod(pMethProp, pObject?.Type); } public static MethodOrPropertySymbol FindMostDerivedMethod(MethodOrPropertySymbol pMethProp, CType pType) { bool flag = false; MethodSymbol methodSymbol = pMethProp as MethodSymbol; if (methodSymbol == null) { PropertySymbol propertySymbol = (PropertySymbol)pMethProp; methodSymbol = (propertySymbol.GetterMethod ?? propertySymbol.SetterMethod); if (methodSymbol == null) return null; flag = (propertySymbol is IndexerSymbol); } if (!methodSymbol.isVirtual || pType == null) return methodSymbol; MethodSymbol methodSymbol2 = methodSymbol.swtSlot?.Meth(); if (methodSymbol2 != null) methodSymbol = methodSymbol2; AggregateType aggregateType = pType as AggregateType; if (aggregateType == null) return methodSymbol; AggregateSymbol aggregateSymbol = aggregateType.OwningAggregate; while (aggregateSymbol?.GetBaseAgg() != null) { for (MethodOrPropertySymbol methodOrPropertySymbol = SymbolLoader.LookupAggMember(methodSymbol.name, aggregateSymbol, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol; methodOrPropertySymbol != null; methodOrPropertySymbol = (methodOrPropertySymbol.LookupNext(symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol)) { if (methodOrPropertySymbol.isOverride && methodOrPropertySymbol.swtSlot.Sym != null && methodOrPropertySymbol.swtSlot.Sym == methodSymbol) { if (flag) return ((MethodSymbol)methodOrPropertySymbol).getProperty(); return methodOrPropertySymbol; } } aggregateSymbol = aggregateSymbol.GetBaseAgg(); } return methodSymbol; } private bool HasOptionalParameters() { return FindMostDerivedMethod(_pCurrentSym, _pGroup.OptionalObject)?.HasOptionalParameters() ?? false; } private bool AddArgumentsForOptionalParameters() { if (_pCurrentParameters.Count <= _pArguments.carg) return true; MethodOrPropertySymbol methodOrPropertySymbol = FindMostDerivedMethod(_pCurrentSym, _pGroup.OptionalObject); if (methodOrPropertySymbol == null) return false; int num = _pArguments.carg; int num2 = 0; TypeArray typeArray = TypeManager.SubstTypeArray(_pCurrentParameters, _pCurrentType, _pGroup.TypeArgs); Expr[] array = new Expr[_pCurrentParameters.Count - num]; while (num < typeArray.Count) { if (!methodOrPropertySymbol.IsParameterOptional(num)) return false; array[num2] = GenerateOptionalArgument(methodOrPropertySymbol, typeArray[num], num); num++; num2++; } for (int i = 0; i < num2; i++) { _pArguments.prgexpr.Add(array[i]); } CType[] array2 = new CType[typeArray.Count]; for (int j = 0; j < typeArray.Count; j++) { array2[j] = _pArguments.prgexpr[j].Type; } _pArguments.types = TypeArray.Allocate(array2); _pArguments.carg = typeArray.Count; _bArgumentsChangedForNamedOrOptionalArguments = true; return true; } private static Expr FindArgumentWithName(ArgInfos pArguments, Name pName) { List<Expr> prgexpr = pArguments.prgexpr; for (int i = 0; i < pArguments.carg; i++) { Expr expr = prgexpr[i]; ExprNamedArgumentSpecification exprNamedArgumentSpecification = expr as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification != null && exprNamedArgumentSpecification.Name == pName) return expr; } return null; } private bool NamedArgumentNamesAppearInParameterList(MethodOrPropertySymbol methprop) { List<Name> list = methprop.ParameterNames; HashSet<Name> hashSet = new HashSet<Name>(); for (int i = 0; i < _pArguments.carg; i++) { ExprNamedArgumentSpecification exprNamedArgumentSpecification = _pArguments.prgexpr[i] as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification == null) { if (!list.IsEmpty()) list = list.Tail(); } else { Name name = exprNamedArgumentSpecification.Name; if (!methprop.ParameterNames.Contains(name)) { if (_pInvalidSpecifiedName == null) _pInvalidSpecifiedName = name; return false; } if (!list.Contains(name)) { if (_pNameUsedInPositionalArgument == null) _pNameUsedInPositionalArgument = name; return false; } if (!hashSet.Add(name)) { if (_pDuplicateSpecifiedName == null) _pDuplicateSpecifiedName = name; return false; } } } return true; } private bool GetNextSym(CMemberLookupResults.CMethodIterator iterator) { if (!iterator.MoveNext()) return false; _pCurrentSym = iterator.CurrentSymbol; AggregateType currentType = iterator.CurrentType; if (_pCurrentType != currentType && _pCurrentType != null && !_methList.IsEmpty() && !_methList.Head().mpwi.GetType().IsInterfaceType) return false; _pCurrentType = currentType; while (_HiddenTypes.Contains(_pCurrentType)) { while (iterator.CurrentType == _pCurrentType) { iterator.MoveNext(); } _pCurrentSym = iterator.CurrentSymbol; _pCurrentType = iterator.CurrentType; if (iterator.AtEnd) return false; } return true; } private bool ConstructExpandedParameters() { if (_pCurrentSym == null || _pArguments == null || _pCurrentParameters == null) return false; if ((_fBindFlags & BindingFlag.BIND_NOPARAMS) != 0) return false; if (!_pCurrentSym.isParamArray) return false; int num = 0; for (int i = _pArguments.carg; i < _pCurrentSym.Params.Count; i++) { if (_pCurrentSym.IsParameterOptional(i)) num++; } if (_pArguments.carg + num < _pCurrentParameters.Count - 1) return false; return TryGetExpandedParams(_pCurrentSym.Params, _pArguments.carg, out _pCurrentParameters); } private Result DetermineCurrentTypeArgs() { TypeArray typeArgs = _pGroup.TypeArgs; MethodSymbol methodSymbol = _pCurrentSym as MethodSymbol; if (methodSymbol != null && methodSymbol.typeVars.Count != typeArgs.Count) { if (typeArgs.Count > 0) { if (!(bool)_mwtBadArity) _mwtBadArity.Set(methodSymbol, _pCurrentType); return Result.Failure_NoSearchForExpanded; } if (!MethodTypeInferrer.Infer(_pExprBinder, methodSymbol, _pCurrentParameters, _pArguments, out _pCurrentTypeArgs)) { if (_results.IsBetterUninferableResult(_pCurrentTypeArgs)) { TypeArray typeVars = methodSymbol.typeVars; if (typeVars != null && _pCurrentTypeArgs != null && typeVars.Count == _pCurrentTypeArgs.Count) _mpwiCantInferInstArg.Set(methodSymbol, _pCurrentType, _pCurrentTypeArgs); else _mpwiCantInferInstArg.Set(methodSymbol, _pCurrentType, typeVars); } return Result.Failure_SearchForExpanded; } } else _pCurrentTypeArgs = typeArgs; return Result.Success; } private bool ArgumentsAreConvertible() { bool flag = false; if (_pArguments.carg != 0) { UpdateArguments(); for (int i = 0; i < _pArguments.carg; i++) { CType cType = _pCurrentParameters[i]; if (!TypeBind.CheckConstraints(cType, CheckConstraintsFlags.NoErrors) && !DoesTypeArgumentsContainErrorSym(cType)) { _mpwiParamTypeConstraints.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); return false; } } for (int j = 0; j < _pArguments.carg; j++) { CType cType2 = _pCurrentParameters[j]; flag |= DoesTypeArgumentsContainErrorSym(cType2); Expr expr = _pArguments.prgexpr[j]; ExprNamedArgumentSpecification exprNamedArgumentSpecification = expr as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification != null) expr = exprNamedArgumentSpecification.Value; if (!_pExprBinder.canConvert(expr, cType2) && !flag) { if (j > _nArgBest) { _nArgBest = j; if (!(bool)_results.BestResult) _results.BestResult.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); } else if (j == _nArgBest && _pArguments.types[j] != cType2) { ParameterModifierType parameterModifierType = _pArguments.types[j] as ParameterModifierType; CType cType3 = (parameterModifierType != null) ? parameterModifierType.ParameterType : _pArguments.types[j]; ParameterModifierType parameterModifierType2 = cType2 as ParameterModifierType; CType cType4 = (parameterModifierType2 != null) ? parameterModifierType2.ParameterType : cType2; if (cType3 == cType4 && !(bool)_results.BestResult) _results.BestResult.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs); } return false; } } } if (flag) { if (_results.IsBetterUninferableResult(_pCurrentTypeArgs)) { MethodSymbol methodSymbol = _pCurrentSym as MethodSymbol; if (methodSymbol != null) _results.UninferableResult.Set(methodSymbol, _pCurrentType, _pCurrentTypeArgs); } return false; } return true; } private void UpdateArguments() { _pCurrentParameters = TypeManager.SubstTypeArray(_pCurrentParameters, _pCurrentType, _pCurrentTypeArgs); if (_pArguments.prgexpr != null && _pArguments.prgexpr.Count != 0) { MethodOrPropertySymbol methodOrPropertySymbol = null; for (int i = 0; i < _pCurrentParameters.Count; i++) { Expr expr = _pArguments.prgexpr[i]; if (expr.IsOptionalArgument) { CType cType = _pCurrentParameters[i]; if (cType != expr.Type) { if (methodOrPropertySymbol == null) methodOrPropertySymbol = FindMostDerivedMethod(_pCurrentSym, _pGroup.OptionalObject); Expr value = GenerateOptionalArgument(methodOrPropertySymbol, _pCurrentParameters[i], i); _pArguments.prgexpr[i] = value; } } } } } private static bool DoesTypeArgumentsContainErrorSym(CType var) { AggregateType aggregateType = var as AggregateType; if (aggregateType == null) return false; TypeArray typeArgsAll = aggregateType.TypeArgsAll; for (int i = 0; i < typeArgsAll.Count; i++) { CType cType = typeArgsAll[i]; if (cType == null) return true; if (cType is AggregateType && DoesTypeArgumentsContainErrorSym(cType)) return true; } return false; } private void ReportErrorsOnSuccess() { if (_pGroup.SymKind == SYMKIND.SK_MethodSymbol && _results.BestResult.TypeArgs.Count > 0) TypeBind.CheckMethConstraints(new MethWithInst(_results.BestResult)); } private RuntimeBinderException ReportErrorsOnFailure() { if (_pDuplicateSpecifiedName != null) return ErrorHandling.Error(ErrorCode.ERR_DuplicateNamedArgument, _pDuplicateSpecifiedName); if ((bool)_results.InaccessibleResult) return CSemanticChecker.ReportAccessError(_results.InaccessibleResult, _pExprBinder.ContextForMemberLookup, GetTypeQualifier(_pGroup)); if ((bool)_misnamed) { List<Name> parameterNames = FindMostDerivedMethod(_misnamed.MethProp(), _pGroup.OptionalObject).ParameterNames; for (int i = 0; i != _pOriginalArguments.carg; i++) { ExprNamedArgumentSpecification exprNamedArgumentSpecification = _pOriginalArguments.prgexpr[i] as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification != null) { Name name = exprNamedArgumentSpecification.Name; if (parameterNames[i] != name) { if (!parameterNames.Contains(name)) { _pInvalidSpecifiedName = name; break; } return ErrorHandling.Error(ErrorCode.ERR_BadNonTrailingNamedArgument, name); } } } } else if ((bool)_mpwiBogus) { return ErrorHandling.Error(ErrorCode.ERR_BindToBogus, _mpwiBogus); } bool flag = false; Name name2 = _pGroup.Name; if (_pGroup.OptionalObject?.Type != null && _pGroup.OptionalObject.Type.IsDelegateType && _pGroup.Name == NameManager.GetPredefinedName(PredefinedName.PN_INVOKE)) { flag = true; name2 = ((AggregateType)_pGroup.OptionalObject.Type).OwningAggregate.name; } if ((bool)_results.BestResult) return ReportErrorsForBestMatching(flag); if ((bool)_results.UninferableResult || (bool)_mpwiCantInferInstArg) { if (!(bool)_results.UninferableResult) _results.UninferableResult.Set(_mpwiCantInferInstArg.Sym as MethodSymbol, _mpwiCantInferInstArg.GetType(), _mpwiCantInferInstArg.TypeArgs); MethWithType swt = new MethWithType(_results.UninferableResult.Meth(), _results.UninferableResult.GetType()); return ErrorHandling.Error(ErrorCode.ERR_CantInferMethTypeArgs, swt); } if ((bool)_mwtBadArity) { int count = _mwtBadArity.Meth().typeVars.Count; return ErrorHandling.Error((count > 0) ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _mwtBadArity, new ErrArgSymKind(_mwtBadArity.Meth()), _pArguments.carg); } if ((bool)_mpwiParamTypeConstraints) { TypeBind.CheckMethConstraints(new MethWithInst(_mpwiParamTypeConstraints)); return null; } if (_pInvalidSpecifiedName != null) { AggregateType aggregateType = _pGroup.OptionalObject?.Type as AggregateType; if (aggregateType == null || !aggregateType.OwningAggregate.IsDelegate()) return ErrorHandling.Error(ErrorCode.ERR_BadNamedArgument, _pGroup.Name, _pInvalidSpecifiedName); return ErrorHandling.Error(ErrorCode.ERR_BadNamedArgumentForDelegateInvoke, aggregateType.OwningAggregate.name, _pInvalidSpecifiedName); } if (_pNameUsedInPositionalArgument != null) return ErrorHandling.Error(ErrorCode.ERR_NamedArgumentUsedInPositional, _pNameUsedInPositionalArgument); if (_fCandidatesUnsupported) return ErrorHandling.Error(ErrorCode.ERR_BindToBogus, name2); if (flag) return ErrorHandling.Error(ErrorCode.ERR_BadDelArgCount, name2, _pArguments.carg); if ((_pGroup.Flags & EXPRFLAG.EXF_CTOR) != 0) return ErrorHandling.Error(ErrorCode.ERR_BadCtorArgCount, _pGroup.ParentType, _pArguments.carg); return ErrorHandling.Error(ErrorCode.ERR_BadArgCount, name2, _pArguments.carg); } private RuntimeBinderException ReportErrorsForBestMatching(bool bUseDelegateErrors) { if (bUseDelegateErrors) return ErrorHandling.Error(ErrorCode.ERR_BadDelArgTypes, _results.BestResult.GetType()); return ErrorHandling.Error(ErrorCode.ERR_BadArgTypes, _results.BestResult); } } internal sealed class GroupToArgsBinderResult { public MethPropWithInst BestResult { get; set; } public MethPropWithInst InaccessibleResult { get; } public MethPropWithInst UninferableResult { get; } public GroupToArgsBinderResult() { BestResult = new MethPropWithInst(); InaccessibleResult = new MethPropWithInst(); UninferableResult = new MethPropWithInst(); } private static int NumberOfErrorTypes(TypeArray pTypeArgs) { int num = 0; for (int i = 0; i < pTypeArgs.Count; i++) { if (pTypeArgs[i] == null) num++; } return num; } private static bool IsBetterThanCurrent(TypeArray pTypeArgs1, TypeArray pTypeArgs2) { int num = NumberOfErrorTypes(pTypeArgs1); int num2 = NumberOfErrorTypes(pTypeArgs2); if (num == num2) { int num3 = (pTypeArgs1.Count > pTypeArgs2.Count) ? pTypeArgs2.Count : pTypeArgs1.Count; for (int i = 0; i < num3; i++) { AggregateType aggregateType = pTypeArgs1[i] as AggregateType; if (aggregateType != null) num += NumberOfErrorTypes(aggregateType.TypeArgsAll); AggregateType aggregateType2 = pTypeArgs2[i] as AggregateType; if (aggregateType2 != null) num2 += NumberOfErrorTypes(aggregateType2.TypeArgsAll); } } return num2 < num; } public bool IsBetterUninferableResult(TypeArray pTypeArguments) { if (UninferableResult.Sym == null) return true; if (pTypeArguments == null) return false; return IsBetterThanCurrent(UninferableResult.TypeArgs, pTypeArguments); } } private sealed class ImplicitConversion { private Expr _exprDest; private readonly ExpressionBinder _binder; private readonly Expr _exprSrc; private readonly CType _typeSrc; private readonly CType _typeDest; private readonly bool _needsExprDest; private CONVERTTYPE _flags; public Expr ExprDest => _exprDest; public ImplicitConversion(ExpressionBinder binder, Expr exprSrc, CType typeSrc, CType typeDest, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; } public bool Bind() { if (_typeSrc != null && _typeDest != null && !(_typeDest is MethodGroupType)) { switch (_typeDest.TypeKind) { case TypeKind.TK_NullType: if (!(_typeSrc is NullType)) return false; if (_needsExprDest) _exprDest = _exprSrc; return true; case TypeKind.TK_ArgumentListType: return _typeSrc == _typeDest; case TypeKind.TK_VoidType: return false; default: { if (_typeSrc == _typeDest && ((_flags & CONVERTTYPE.ISEXPLICIT) == (CONVERTTYPE)0 || (!_typeSrc.IsPredefType(PredefinedType.PT_FLOAT) && !_typeSrc.IsPredefType(PredefinedType.PT_DOUBLE)))) { if (_needsExprDest) _exprDest = _exprSrc; return true; } NullableType nullableType = _typeDest as NullableType; if (nullableType != null) return BindNubConversion(nullableType); NullableType nullableType2 = _typeSrc as NullableType; if (nullableType2 != null) return bindImplicitConversionFromNullable(nullableType2); if ((_flags & CONVERTTYPE.ISEXPLICIT) != 0) _flags |= CONVERTTYPE.NOUDC; FUNDTYPE fundamentalType = _typeDest.FundamentalType; switch (_typeSrc.TypeKind) { case TypeKind.TK_VoidType: case TypeKind.TK_ArgumentListType: case TypeKind.TK_ParameterModifierType: return false; case TypeKind.TK_NullType: if (bindImplicitConversionFromNull()) return true; break; case TypeKind.TK_ArrayType: if (bindImplicitConversionFromArray()) return true; break; case TypeKind.TK_PointerType: if (bindImplicitConversionFromPointer()) return true; break; case TypeKind.TK_AggregateType: if (bindImplicitConversionFromAgg(_typeSrc as AggregateType)) return true; break; } object obj = _exprSrc?.RuntimeObject; if (obj != null && _typeDest.AssociatedSystemType.IsInstanceOfType(obj) && CSemanticChecker.CheckTypeAccess(_typeDest, _binder.Context.ContextForMemberLookup)) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, _exprSrc.Flags & EXPRFLAG.EXF_CANTBENULL); return true; } if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, true); return false; } } } return false; } private bool BindNubConversion(NullableType nubDst) { AggregateType ats = nubDst.GetAts(); if (SymbolLoader.HasBaseConversion(nubDst.UnderlyingType, _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst)) { if ((_flags & CONVERTTYPE.ISEXPLICIT) == (CONVERTTYPE)0) return false; if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_INDEXER); return true; } bool wasNullable; CType cType = nubDst.StripNubs(out wasNullable); bool wasNullable2; CType cType2 = _typeSrc.StripNubs(out wasNullable2); ConversionFunc conversionFunc = ((_flags & CONVERTTYPE.ISEXPLICIT) != 0) ? new ConversionFunc(_binder.BindExplicitConversion) : new ConversionFunc(_binder.BindImplicitConversion); if (!wasNullable2) { if (_typeSrc is NullType) { if (_needsExprDest) _exprDest = ((_exprSrc is ExprConstant) ? ExprFactory.CreateZeroInit(nubDst) : ExprFactory.CreateCast(_typeDest, _exprSrc)); return true; } Expr ppDestinationExpr = _exprSrc; if (_typeSrc == cType || conversionFunc(_exprSrc, _typeSrc, cType, _needsExprDest, out ppDestinationExpr, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { ExprUserDefinedConversion exprUserDefinedConversion = ppDestinationExpr as ExprUserDefinedConversion; if (exprUserDefinedConversion != null) ppDestinationExpr = exprUserDefinedConversion.UserDefinedCall; if (wasNullable) { ExprCall exprCall = BindNubNew(ppDestinationExpr); ppDestinationExpr = exprCall; exprCall.NullableCallLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUserDefinedConversion != null) { exprUserDefinedConversion.UserDefinedCall = ppDestinationExpr; ppDestinationExpr = exprUserDefinedConversion; } _exprDest = ppDestinationExpr; } return true; } if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, (_flags & CONVERTTYPE.ISEXPLICIT) == (CONVERTTYPE)0); return false; } if (cType2 != cType && !conversionFunc(null, cType2, cType, false, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, (_flags & CONVERTTYPE.ISEXPLICIT) == (CONVERTTYPE)0); return false; } if (_needsExprDest) { MethWithInst method = new MethWithInst(null, null); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, method); ExprCall exprCall2 = ExprFactory.CreateCall((EXPRFLAG)0, nubDst, _exprSrc, memberGroup, null); Expr ppDestinationExpr2 = _binder.mustCast(_exprSrc, cType2); if (!(((_flags & CONVERTTYPE.ISEXPLICIT) != 0) ? _binder.BindExplicitConversion(ppDestinationExpr2, ppDestinationExpr2.Type, cType, out ppDestinationExpr2, _flags | CONVERTTYPE.NOUDC) : _binder.BindImplicitConversion(ppDestinationExpr2, ppDestinationExpr2.Type, cType, out ppDestinationExpr2, _flags | CONVERTTYPE.NOUDC))) return false; exprCall2.CastOfNonLiftedResultToLiftedType = _binder.mustCast(ppDestinationExpr2, nubDst, (CONVERTTYPE)0); exprCall2.NullableCallLiftKind = NullableCallLiftKind.NullableConversion; exprCall2.PConversions = exprCall2.CastOfNonLiftedResultToLiftedType; _exprDest = exprCall2; } return true; } private bool bindImplicitConversionFromNull() { FUNDTYPE fundamentalType = _typeDest.FundamentalType; if (fundamentalType != FUNDTYPE.FT_REF && fundamentalType != FUNDTYPE.FT_PTR && !_typeDest.IsPredefType(PredefinedType.PT_G_OPTIONAL)) return false; if (_needsExprDest) _exprDest = ((_exprSrc is ExprConstant) ? ExprFactory.CreateZeroInit(_typeDest) : ExprFactory.CreateCast(_typeDest, _exprSrc)); return true; } private bool bindImplicitConversionFromNullable(NullableType nubSrc) { AggregateType ats = nubSrc.GetAts(); if (ats == _typeDest) { if (_needsExprDest) _exprDest = _exprSrc; return true; } if (SymbolLoader.HasBaseConversion(nubSrc.UnderlyingType, _typeDest) && !CConversions.FUnwrappingConv(nubSrc, _typeDest)) { if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_CTOR); if (!_typeDest.IsPredefType(PredefinedType.PT_OBJECT)) _binder.bindSimpleCast(_exprDest, _typeDest, out _exprDest, EXPRFLAG.EXF_ASFINALLYLEAVE); } return true; } if ((_flags & CONVERTTYPE.NOUDC) == (CONVERTTYPE)0) return _binder.bindUserDefinedConversion(_exprSrc, nubSrc, _typeDest, _needsExprDest, out _exprDest, true); return false; } private bool bindImplicitConversionFromArray() { if (!SymbolLoader.HasBaseConversion(_typeSrc, _typeDest)) return false; EXPRFLAG exprFlags = (EXPRFLAG)0; if (!(_typeDest is ArrayType)) { AggregateType aggregateType = _typeDest as AggregateType; if (aggregateType == null || !aggregateType.IsInterfaceType || aggregateType.TypeArgsAll.Count != 1 || (aggregateType.TypeArgsAll[0] == ((ArrayType)_typeSrc).ElementType && (_flags & CONVERTTYPE.FORCECAST) == (CONVERTTYPE)0)) goto IL_009b; } if ((_flags & CONVERTTYPE.FORCECAST) != 0 || TypeManager.TypeContainsTyVars(_typeSrc, null) || TypeManager.TypeContainsTyVars(_typeDest, null)) exprFlags = EXPRFLAG.EXF_OPERATOR; goto IL_009b; IL_009b: if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, exprFlags); return true; } private bool bindImplicitConversionFromPointer() { PointerType pointerType = _typeDest as PointerType; if (pointerType != null && pointerType.ReferentType == VoidType.Instance) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return true; } return false; } private bool bindImplicitConversionFromAgg(AggregateType aggTypeSrc) { AggregateSymbol owningAggregate = aggTypeSrc.OwningAggregate; if (owningAggregate.IsEnum()) return bindImplicitConversionFromEnum(aggTypeSrc); if (_typeDest.IsEnumType) { if (bindImplicitConversionToEnum(aggTypeSrc)) return true; } else if (owningAggregate.getThisType().IsSimpleType && _typeDest.IsSimpleType && bindImplicitConversionBetweenSimpleTypes(aggTypeSrc)) { return true; } return bindImplicitConversionToBase(aggTypeSrc); } private bool bindImplicitConversionToBase(AggregateType pSource) { if (!(_typeDest is AggregateType) || !SymbolLoader.HasBaseConversion(pSource, _typeDest)) return false; EXPRFLAG exprFlags = (EXPRFLAG)0; if (pSource.OwningAggregate.IsStruct() && _typeDest.FundamentalType == FUNDTYPE.FT_REF) exprFlags = (EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_CANTBENULL); else if (_exprSrc != null) { exprFlags = (_exprSrc.Flags & EXPRFLAG.EXF_CANTBENULL); } if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, exprFlags); return true; } private bool bindImplicitConversionFromEnum(AggregateType aggTypeSrc) { AggregateType aggregateType = _typeDest as AggregateType; if (aggregateType != null && SymbolLoader.HasBaseConversion(aggTypeSrc, aggregateType)) { if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_CANTBENULL); return true; } return false; } private bool bindImplicitConversionToEnum(AggregateType aggTypeSrc) { if (aggTypeSrc.OwningAggregate.GetPredefType() != PredefinedType.PT_BOOL && _exprSrc != null && _exprSrc.IsZero() && _exprSrc.Type.IsNumericType && (_flags & CONVERTTYPE.STANDARD) == (CONVERTTYPE)0) { if (_needsExprDest) _exprDest = ExprFactory.CreateConstant(_typeDest, ConstVal.GetDefaultValue(_typeDest.ConstValKind)); return true; } return false; } private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc) { AggregateSymbol owningAggregate = aggTypeSrc.OwningAggregate; PredefinedType predefType = owningAggregate.GetPredefType(); PredefinedType predefinedType = _typeDest.PredefinedType; ExprConstant exprConstant = _exprSrc as ExprConstant; ConvKind convKind = (exprConstant != null && ((predefType == PredefinedType.PT_INT && predefinedType != PredefinedType.PT_BOOL && predefinedType != PredefinedType.PT_CHAR) || (predefType == PredefinedType.PT_LONG && predefinedType == PredefinedType.PT_ULONG)) && isConstantInRange(exprConstant, _typeDest)) ? ConvKind.Implicit : ((predefType != predefinedType) ? GetConvKind(predefType, predefinedType) : ConvKind.Implicit); if (convKind != ConvKind.Implicit) return false; if (_exprSrc.GetConst() != null && _binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, false) == ConstCastResult.Success) return true; if (isUserDefinedConversion(predefType, predefinedType)) { if (!_needsExprDest) return true; return _binder.bindUserDefinedConversion(_exprSrc, aggTypeSrc, _typeDest, _needsExprDest, out _exprDest, true); } if (_needsExprDest) _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest); return true; } } private class UnaOpSig { public PredefinedType pt; public UnaOpMask grfuom; public int cuosSkip; public PfnBindUnaOp pfn; public UnaOpFuncKind fnkind; protected UnaOpSig() { } public UnaOpSig(PredefinedType pt, UnaOpMask grfuom, int cuosSkip, PfnBindUnaOp pfn, UnaOpFuncKind fnkind) { this.pt = pt; this.grfuom = grfuom; this.cuosSkip = cuosSkip; this.pfn = pfn; this.fnkind = fnkind; } } private sealed class UnaOpFullSig : UnaOpSig { private readonly LiftFlags _grflt; private readonly CType _type; public UnaOpFullSig(CType type, PfnBindUnaOp pfn, LiftFlags grflt, UnaOpFuncKind fnkind) { pt = PredefinedType.PT_UNDEFINEDINDEX; grfuom = UnaOpMask.None; cuosSkip = 0; base.pfn = pfn; _type = type; _grflt = grflt; base.fnkind = fnkind; } public UnaOpFullSig(ExpressionBinder fnc, UnaOpSig uos) { pt = uos.pt; grfuom = uos.grfuom; cuosSkip = uos.cuosSkip; pfn = uos.pfn; fnkind = uos.fnkind; _type = ((pt != PredefinedType.PT_UNDEFINEDINDEX) ? GetPredefindType(pt) : null); _grflt = LiftFlags.None; } public bool FPreDef() { return pt != PredefinedType.PT_UNDEFINEDINDEX; } public bool isLifted() { if (_grflt == LiftFlags.None) return false; return true; } public bool Convert() { return (_grflt & LiftFlags.Convert1) != LiftFlags.None; } public new CType GetType() { return _type; } } private static readonly byte[][] s_betterConversionTable = new byte[16][] { new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3 }, new byte[16] { 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 } }; private static readonly byte[][] s_simpleTypeConversions = new byte[13][] { new byte[13] { 1, 2, 2, 2, 2, 2, 66, 3, 5, 3, 2, 2, 2 }, new byte[13] { 3, 1, 2, 2, 2, 2, 66, 3, 5, 3, 3, 3, 3 }, new byte[13] { 3, 3, 1, 2, 2, 2, 66, 3, 5, 3, 3, 3, 3 }, new byte[13] { 3, 3, 3, 1, 2, 2, 66, 3, 5, 3, 3, 3, 3 }, new byte[13] { 3, 3, 3, 3, 1, 2, 67, 3, 5, 3, 3, 3, 3 }, new byte[13] { 3, 3, 3, 3, 3, 1, 67, 3, 5, 3, 3, 3, 3 }, new byte[13] { 67, 67, 67, 67, 67, 67, 1, 67, 5, 67, 67, 67, 67 }, new byte[13] { 3, 3, 2, 2, 2, 2, 66, 1, 5, 3, 2, 2, 2 }, new byte[13] { 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5 }, new byte[13] { 3, 2, 2, 2, 2, 2, 66, 3, 5, 1, 3, 3, 3 }, new byte[13] { 3, 3, 2, 2, 2, 2, 66, 3, 5, 3, 1, 2, 2 }, new byte[13] { 3, 3, 3, 2, 2, 2, 66, 3, 5, 3, 3, 1, 2 }, new byte[13] { 3, 3, 3, 3, 2, 2, 66, 3, 5, 3, 3, 3, 1 } }; private static readonly byte[][] s_simpleTypeBetter = new byte[16][] { new byte[16] { 0, 1, 1, 1, 1, 1, 1, 3, 3, 2, 1, 1, 1, 3, 3, 1 }, new byte[16] { 2, 0, 1, 1, 1, 1, 1, 3, 3, 2, 1, 1, 1, 3, 3, 1 }, new byte[16] { 2, 2, 0, 1, 1, 1, 1, 2, 3, 2, 2, 1, 1, 3, 3, 1 }, new byte[16] { 2, 2, 2, 0, 1, 1, 1, 2, 3, 2, 2, 2, 1, 3, 3, 1 }, new byte[16] { 2, 2, 2, 2, 0, 1, 3, 2, 3, 2, 2, 2, 2, 3, 3, 1 }, new byte[16] { 2, 2, 2, 2, 2, 0, 3, 2, 3, 2, 2, 2, 2, 3, 3, 1 }, new byte[16] { 2, 2, 2, 2, 3, 3, 0, 2, 3, 2, 2, 2, 2, 3, 3, 1 }, new byte[16] { 3, 3, 1, 1, 1, 1, 1, 0, 3, 3, 1, 1, 1, 3, 3, 1 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 1 }, new byte[16] { 1, 1, 1, 1, 1, 1, 1, 3, 3, 0, 1, 1, 1, 3, 3, 1 }, new byte[16] { 2, 2, 1, 1, 1, 1, 1, 2, 3, 2, 0, 1, 1, 3, 3, 1 }, new byte[16] { 2, 2, 2, 1, 1, 1, 1, 2, 3, 2, 2, 0, 1, 3, 3, 1 }, new byte[16] { 2, 2, 2, 2, 1, 1, 1, 2, 3, 2, 2, 2, 0, 3, 3, 1 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 1 }, new byte[16] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1 }, new byte[16] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 } }; private static readonly PredefinedType[] s_rgptIntOp = new PredefinedType[4] { PredefinedType.PT_INT, PredefinedType.PT_UINT, PredefinedType.PT_LONG, PredefinedType.PT_ULONG }; private static readonly PredefinedName[] s_EK2NAME = new PredefinedName[26] { PredefinedName.PN_OPEQUALS, PredefinedName.PN_OPCOMPARE, PredefinedName.PN_OPTRUE, PredefinedName.PN_OPFALSE, PredefinedName.PN_OPINCREMENT, PredefinedName.PN_OPDECREMENT, PredefinedName.PN_OPNEGATION, PredefinedName.PN_OPEQUALITY, PredefinedName.PN_OPINEQUALITY, PredefinedName.PN_OPLESSTHAN, PredefinedName.PN_OPLESSTHANOREQUAL, PredefinedName.PN_OPGREATERTHAN, PredefinedName.PN_OPGREATERTHANOREQUAL, PredefinedName.PN_OPPLUS, PredefinedName.PN_OPMINUS, PredefinedName.PN_OPMULTIPLY, PredefinedName.PN_OPDIVISION, PredefinedName.PN_OPMODULUS, PredefinedName.PN_OPUNARYMINUS, PredefinedName.PN_OPUNARYPLUS, PredefinedName.PN_OPBITWISEAND, PredefinedName.PN_OPBITWISEOR, PredefinedName.PN_OPXOR, PredefinedName.PN_OPCOMPLEMENT, PredefinedName.PN_OPLEFTSHIFT, PredefinedName.PN_OPRIGHTSHIFT }; private static readonly BinOpSig[] s_binopSignatures = new BinOpSig[20] { new BinOpSig(PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Integer, 8, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp), new BinOpSig(PredefinedType.PT_UINT, PredefinedType.PT_UINT, BinOpMask.Integer, 7, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp), new BinOpSig(PredefinedType.PT_LONG, PredefinedType.PT_LONG, BinOpMask.Integer, 6, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp), new BinOpSig(PredefinedType.PT_ULONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 5, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp), new BinOpSig(PredefinedType.PT_ULONG, PredefinedType.PT_LONG, BinOpMask.Integer, 4, null, OpSigFlags.Value, BinOpFuncKind.None), new BinOpSig(PredefinedType.PT_LONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 3, null, OpSigFlags.Value, BinOpFuncKind.None), new BinOpSig(PredefinedType.PT_FLOAT, PredefinedType.PT_FLOAT, BinOpMask.Real, 1, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp), new BinOpSig(PredefinedType.PT_DOUBLE, PredefinedType.PT_DOUBLE, BinOpMask.Real, 0, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp), new BinOpSig(PredefinedType.PT_DECIMAL, PredefinedType.PT_DECIMAL, BinOpMask.Real, 0, BindDecBinOp, OpSigFlags.Value, BinOpFuncKind.DecBinOp), new BinOpSig(PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Equal, 0, BindStrCmpOp, OpSigFlags.Convert, BinOpFuncKind.StrCmpOp), new BinOpSig(PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Add, 2, BindStrBinOp, OpSigFlags.Convert, BinOpFuncKind.StrBinOp), new BinOpSig(PredefinedType.PT_STRING, PredefinedType.PT_OBJECT, BinOpMask.Add, 1, BindStrBinOp, OpSigFlags.Convert, BinOpFuncKind.StrBinOp), new BinOpSig(PredefinedType.PT_OBJECT, PredefinedType.PT_STRING, BinOpMask.Add, 0, BindStrBinOp, OpSigFlags.Convert, BinOpFuncKind.StrBinOp), new BinOpSig(PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Shift, 3, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp), new BinOpSig(PredefinedType.PT_UINT, PredefinedType.PT_INT, BinOpMask.Shift, 2, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp), new BinOpSig(PredefinedType.PT_LONG, PredefinedType.PT_INT, BinOpMask.Shift, 1, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp), new BinOpSig(PredefinedType.PT_ULONG, PredefinedType.PT_INT, BinOpMask.Shift, 0, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp), new BinOpSig(PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.BoolNorm, 0, BindBoolBinOp, OpSigFlags.Value, BinOpFuncKind.BoolBinOp), new BinOpSig(PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Logical, 0, BindBoolBinOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBinOp), new BinOpSig(PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Bitwise, 0, BindLiftedBoolBitwiseOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBitwiseOp) }; private static readonly UnaOpSig[] s_rguos = new UnaOpSig[16] { new UnaOpSig(PredefinedType.PT_INT, UnaOpMask.Signed, 7, BindIntUnaOp, UnaOpFuncKind.IntUnaOp), new UnaOpSig(PredefinedType.PT_UINT, UnaOpMask.Unsigned, 6, BindIntUnaOp, UnaOpFuncKind.IntUnaOp), new UnaOpSig(PredefinedType.PT_LONG, UnaOpMask.Signed, 5, BindIntUnaOp, UnaOpFuncKind.IntUnaOp), new UnaOpSig(PredefinedType.PT_ULONG, UnaOpMask.Unsigned, 4, BindIntUnaOp, UnaOpFuncKind.IntUnaOp), new UnaOpSig(PredefinedType.PT_ULONG, UnaOpMask.Minus, 3, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_FLOAT, UnaOpMask.Real, 1, BindRealUnaOp, UnaOpFuncKind.RealUnaOp), new UnaOpSig(PredefinedType.PT_DOUBLE, UnaOpMask.Real, 0, BindRealUnaOp, UnaOpFuncKind.RealUnaOp), new UnaOpSig(PredefinedType.PT_DECIMAL, UnaOpMask.Real, 0, BindDecUnaOp, UnaOpFuncKind.DecUnaOp), new UnaOpSig(PredefinedType.PT_BOOL, UnaOpMask.Bang, 0, BindBoolUnaOp, UnaOpFuncKind.BoolUnaOp), new UnaOpSig(PredefinedType.PT_INT, UnaOpMask.IncDec, 6, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_UINT, UnaOpMask.IncDec, 5, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_LONG, UnaOpMask.IncDec, 4, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_ULONG, UnaOpMask.IncDec, 3, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_FLOAT, UnaOpMask.IncDec, 1, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_DOUBLE, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None), new UnaOpSig(PredefinedType.PT_DECIMAL, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None) }; public BindingContext Context { get; } private AggregateSymbol ContextForMemberLookup => Context.ContextForMemberLookup; private static BetterType WhichMethodIsBetterTieBreaker(CandidateFunctionMember node1, CandidateFunctionMember node2, CType pTypeThrough, ArgInfos args) { MethPropWithInst mpwi = node1.mpwi; MethPropWithInst mpwi2 = node2.mpwi; if (node1.ctypeLift != node2.ctypeLift) { if (node1.ctypeLift >= node2.ctypeLift) return BetterType.Right; return BetterType.Left; } if (mpwi.TypeArgs.Count != 0) { if (mpwi2.TypeArgs.Count == 0) return BetterType.Right; } else if (mpwi2.TypeArgs.Count != 0) { return BetterType.Left; } if (node1.fExpanded) { if (!node2.fExpanded) return BetterType.Right; } else if (node2.fExpanded) { return BetterType.Left; } BetterType betterType = CompareTypes(RearrangeNamedArguments(mpwi.MethProp().Params, mpwi, pTypeThrough, args), RearrangeNamedArguments(mpwi2.MethProp().Params, mpwi2, pTypeThrough, args)); if (betterType == BetterType.Left || betterType == BetterType.Right) return betterType; if (mpwi.MethProp().modOptCount != mpwi2.MethProp().modOptCount) { if (mpwi.MethProp().modOptCount >= mpwi2.MethProp().modOptCount) return BetterType.Right; return BetterType.Left; } return BetterType.Neither; } private static BetterType CompareTypes(TypeArray ta1, TypeArray ta2) { if (ta1 == ta2) return BetterType.Same; if (ta1.Count != ta2.Count) { if (ta1.Count <= ta2.Count) return BetterType.Right; return BetterType.Left; } BetterType betterType = BetterType.Neither; for (int i = 0; i < ta1.Count; i++) { CType cType = ta1[i]; CType cType2 = ta2[i]; BetterType betterType2 = BetterType.Neither; while (true) { if (cType.TypeKind != cType2.TypeKind) { if (cType is TypeParameterType) betterType2 = BetterType.Right; else if (cType2 is TypeParameterType) { betterType2 = BetterType.Left; } break; } switch (cType.TypeKind) { case TypeKind.TK_ArrayType: case TypeKind.TK_PointerType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_NullableType: break; case TypeKind.TK_AggregateType: betterType2 = CompareTypes(((AggregateType)cType).TypeArgsAll, ((AggregateType)cType2).TypeArgsAll); goto end_IL_0042; default: goto end_IL_0042; } cType = cType.BaseOrParameterOrElementType; cType2 = cType2.BaseOrParameterOrElementType; continue; continue; end_IL_0042: break; } if (betterType2 == BetterType.Right || betterType2 == BetterType.Left) { if (betterType == BetterType.Same || betterType == BetterType.Neither) betterType = betterType2; else if (betterType2 != betterType) { return BetterType.Neither; } } } return betterType; } private static int FindName(List<Name> names, Name name) { return names.IndexOf(name); } private static TypeArray RearrangeNamedArguments(TypeArray pta, MethPropWithInst mpwi, CType pTypeThrough, ArgInfos args) { if (args.carg == 0 || !(args.prgexpr[args.carg - 1] is ExprNamedArgumentSpecification)) return pta; CType pType = (pTypeThrough != null) ? pTypeThrough : mpwi.GetType(); CType[] array = new CType[pta.Count]; MethodOrPropertySymbol methodOrPropertySymbol = GroupToArgsBinder.FindMostDerivedMethod(mpwi.MethProp(), pType); for (int i = 0; i < pta.Count; i++) { array[i] = pta[i]; } List<Expr> prgexpr = args.prgexpr; for (int j = 0; j < args.carg; j++) { ExprNamedArgumentSpecification exprNamedArgumentSpecification = prgexpr[j] as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification != null) { int num = FindName(methodOrPropertySymbol.ParameterNames, exprNamedArgumentSpecification.Name); CType cType = pta[num]; for (int k = j; k < num; k++) { array[k + 1] = array[k]; } array[j] = cType; } } return TypeArray.Allocate(array); } private BetterType WhichMethodIsBetter(CandidateFunctionMember node1, CandidateFunctionMember node2, CType pTypeThrough, ArgInfos args) { MethPropWithInst mpwi = node1.mpwi; MethPropWithInst mpwi2 = node2.mpwi; TypeArray typeArray = RearrangeNamedArguments(node1.params, mpwi, pTypeThrough, args); TypeArray typeArray2 = RearrangeNamedArguments(node2.params, mpwi2, pTypeThrough, args); if (typeArray == typeArray2) return WhichMethodIsBetterTieBreaker(node1, node2, pTypeThrough, args); BetterType betterType = BetterType.Neither; int carg = args.carg; for (int i = 0; i < carg; i++) { Expr expr = args.prgexpr[i]; CType p = typeArray[i]; CType p2 = typeArray2[i]; CType argType = expr?.RuntimeObjectActualType ?? args.types[i]; BetterType betterType2 = WhichConversionIsBetter(argType, p, p2); switch (betterType) { case BetterType.Right: break; case BetterType.Left: goto IL_00b9; default: goto IL_00c3; } if (betterType2 == BetterType.Left) { betterType = BetterType.Neither; break; } continue; IL_00b9: if (betterType2 == BetterType.Right) { betterType = BetterType.Neither; break; } continue; IL_00c3: if (betterType2 == BetterType.Right || betterType2 == BetterType.Left) betterType = betterType2; } if (typeArray.Count != typeArray2.Count && betterType == BetterType.Neither) { if (node1.fExpanded) { if (!node2.fExpanded) return BetterType.Right; } else if (node2.fExpanded) { return BetterType.Left; } if (typeArray.Count == carg) return BetterType.Left; if (typeArray2.Count == carg) return BetterType.Right; return BetterType.Neither; } return betterType; } private BetterType WhichConversionIsBetter(CType argType, CType p1, CType p2) { if (p1 == p2) return BetterType.Same; if (argType == p1) return BetterType.Left; if (argType == p2) return BetterType.Right; bool flag = canConvert(p1, p2); bool flag2 = canConvert(p2, p1); if (flag != flag2) { if (!flag) return BetterType.Right; return BetterType.Left; } if (p1.IsPredefined && p2.IsPredefined) { PredefinedType predefinedType = p1.PredefinedType; if (predefinedType <= PredefinedType.PT_OBJECT) { PredefinedType predefinedType2 = p2.PredefinedType; if (predefinedType2 <= PredefinedType.PT_OBJECT) return (BetterType)s_betterConversionTable[(uint)predefinedType][(uint)predefinedType2]; } } return BetterType.Neither; } private CandidateFunctionMember FindBestMethod(List<CandidateFunctionMember> list, CType pTypeThrough, ArgInfos args, out CandidateFunctionMember methAmbig1, out CandidateFunctionMember methAmbig2) { CandidateFunctionMember candidateFunctionMember = null; CandidateFunctionMember candidateFunctionMember2 = null; bool flag = false; CandidateFunctionMember candidateFunctionMember3 = list[0]; for (int i = 1; i < list.Count; i++) { CandidateFunctionMember candidateFunctionMember4 = list[i]; switch (WhichMethodIsBetter(candidateFunctionMember3, candidateFunctionMember4, pTypeThrough, args)) { case BetterType.Left: flag = false; break; case BetterType.Right: flag = false; candidateFunctionMember3 = candidateFunctionMember4; break; default: candidateFunctionMember = candidateFunctionMember3; candidateFunctionMember2 = candidateFunctionMember4; i++; if (i < list.Count) { candidateFunctionMember4 = list[i]; candidateFunctionMember3 = candidateFunctionMember4; } else flag = true; break; } } if (!flag) { foreach (CandidateFunctionMember item in list) { if (item != candidateFunctionMember3) { switch (WhichMethodIsBetter(item, candidateFunctionMember3, pTypeThrough, args)) { case BetterType.Left: break; case BetterType.Same: case BetterType.Neither: candidateFunctionMember = candidateFunctionMember3; candidateFunctionMember2 = item; break; case BetterType.Right: continue; } break; } methAmbig1 = null; methAmbig2 = null; return candidateFunctionMember3; } } if ((candidateFunctionMember != null) & (candidateFunctionMember2 != null)) { methAmbig1 = candidateFunctionMember; methAmbig2 = candidateFunctionMember2; } else { methAmbig1 = list.First(); methAmbig2 = list.Skip(1).First(); } return null; } private static void RoundToFloat(double d, out float f) { f = (float)d; } private static long I64(long x) { return x; } private static long I64(ulong x) { return (long)x; } private static ConvKind GetConvKind(PredefinedType ptSrc, PredefinedType ptDst) { if ((int)ptSrc < 13 && (int)ptDst < 13) return (ConvKind)(s_simpleTypeConversions[(uint)ptSrc][(uint)ptDst] & 15); if (ptSrc == ptDst || (ptDst == PredefinedType.PT_OBJECT && ptSrc < PredefinedType.PT_COUNT)) return ConvKind.Implicit; if (ptSrc == PredefinedType.PT_OBJECT && ptDst < PredefinedType.PT_COUNT) return ConvKind.Explicit; return ConvKind.Unknown; } private static bool isUserDefinedConversion(PredefinedType ptSrc, PredefinedType ptDst) { if ((int)ptSrc < 13 && (int)ptDst < 13) return (s_simpleTypeConversions[(uint)ptSrc][(uint)ptDst] & 64) != 0; return false; } private BetterType WhichSimpleConversionIsBetter(PredefinedType pt1, PredefinedType pt2) { return (BetterType)s_simpleTypeBetter[(uint)pt1][(uint)pt2]; } private BetterType WhichTypeIsBetter(PredefinedType pt1, PredefinedType pt2, CType typeGiven) { if (pt1 == pt2) return BetterType.Same; if (typeGiven.IsPredefType(pt1)) return BetterType.Left; if (typeGiven.IsPredefType(pt2)) return BetterType.Right; if ((int)pt1 < 16 && (int)pt2 < 16) return WhichSimpleConversionIsBetter(pt1, pt2); if (pt2 == PredefinedType.PT_OBJECT && pt1 < PredefinedType.PT_COUNT) return BetterType.Left; if (pt1 == PredefinedType.PT_OBJECT && pt2 < PredefinedType.PT_COUNT) return BetterType.Right; return WhichTypeIsBetter(GetPredefindType(pt1), GetPredefindType(pt2), typeGiven); } private BetterType WhichTypeIsBetter(CType type1, CType type2, CType typeGiven) { if (type1 == type2) return BetterType.Same; if (typeGiven == type1) return BetterType.Left; if (typeGiven == type2) return BetterType.Right; bool flag = canConvert(type1, type2); bool flag2 = canConvert(type2, type1); if (flag != flag2) { if (!flag) return BetterType.Right; return BetterType.Left; } NullableType nullableType = type1 as NullableType; if (nullableType != null) { NullableType nullableType2 = type2 as NullableType; if (nullableType2 != null && nullableType.UnderlyingType.IsPredefined && nullableType2.UnderlyingType.IsPredefined) { PredefinedType predefinedType = (type1 as NullableType).UnderlyingType.PredefinedType; PredefinedType predefinedType2 = (type2 as NullableType).UnderlyingType.PredefinedType; if ((int)predefinedType < 16 && (int)predefinedType2 < 16) return WhichSimpleConversionIsBetter(predefinedType, predefinedType2); return BetterType.Neither; } } return BetterType.Neither; } private bool canConvert(CType src, CType dest, CONVERTTYPE flags) { return BindImplicitConversion(null, src, dest, flags); } public bool canConvert(CType src, CType dest) { return canConvert(src, dest, (CONVERTTYPE)0); } private bool canConvert(Expr expr, CType dest) { return canConvert(expr, dest, (CONVERTTYPE)0); } private bool canConvert(Expr expr, CType dest, CONVERTTYPE flags) { return BindImplicitConversion(expr, expr.Type, dest, flags); } private Expr mustConvertCore(Expr expr, CType destExpr) { return mustConvertCore(expr, destExpr, (CONVERTTYPE)0); } private Expr mustConvertCore(Expr expr, CType dest, CONVERTTYPE flags) { if (BindImplicitConversion(expr, expr.Type, dest, out Expr ppDestinationExpr, flags)) { CheckUnsafe(expr.Type); CheckUnsafe(dest); return ppDestinationExpr; } FUNDTYPE fundamentalType = expr.Type.FundamentalType; FUNDTYPE fundamentalType2 = dest.FundamentalType; ExprConstant exprConstant = expr as ExprConstant; if (exprConstant != null && expr.Type.IsSimpleType && dest.IsSimpleType && ((fundamentalType == FUNDTYPE.FT_I4 && (fundamentalType2 <= FUNDTYPE.FT_U4 || fundamentalType2 == FUNDTYPE.FT_U8)) || (fundamentalType == FUNDTYPE.FT_I8 && fundamentalType2 == FUNDTYPE.FT_U8))) { string psz = exprConstant.Int64Value.ToString(CultureInfo.InvariantCulture); throw ErrorHandling.Error(ErrorCode.ERR_ConstOutOfRange, psz, dest); } if (expr.Type is NullType && dest.FundamentalType != FUNDTYPE.FT_REF) throw ErrorHandling.Error(ErrorCode.ERR_ValueCantBeNull, dest); throw ErrorHandling.Error(canCast(expr.Type, dest, flags) ? ErrorCode.ERR_NoImplicitConvCast : ErrorCode.ERR_NoImplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique)); } public Expr tryConvert(Expr expr, CType dest) { return tryConvert(expr, dest, (CONVERTTYPE)0); } private Expr tryConvert(Expr expr, CType dest, CONVERTTYPE flags) { if (BindImplicitConversion(expr, expr.Type, dest, out Expr ppDestinationExpr, flags)) { CheckUnsafe(expr.Type); CheckUnsafe(dest); return ppDestinationExpr; } return null; } public Expr mustConvert(Expr expr, CType dest) { return mustConvert(expr, dest, (CONVERTTYPE)0); } private Expr mustConvert(Expr expr, CType dest, CONVERTTYPE flags) { return mustConvertCore(expr, dest, flags); } private Expr mustCastCore(Expr expr, CType dest, CONVERTTYPE flags) { CSemanticChecker.CheckForStaticClass(dest); if (BindExplicitConversion(expr, expr.Type, dest, out Expr ppDestinationExpr, flags)) { CheckUnsafe(expr.Type); CheckUnsafe(dest); return ppDestinationExpr; } Expr const = expr.GetConst(); if (const != null && expr.Type.IsSimpleOrEnum && dest.IsSimpleOrEnum) { FUNDTYPE fundamentalType = expr.Type.FundamentalType; ConstVal val; if (fundamentalType == FUNDTYPE.FT_STRUCT) { ErrArg[] obj = new ErrArg[2]; val = ((ExprConstant)const).Val; obj[0] = val.DecimalVal.ToString(CultureInfo.InvariantCulture); obj[1] = dest; throw ErrorHandling.Error(ErrorCode.ERR_ConstOutOfRange, obj); } if (Context.Checked) { if (!CanExplicitConversionBeBoundInUncheckedContext(expr, expr.Type, dest, flags | CONVERTTYPE.NOUDC)) throw CantConvert(expr, dest); string psz; switch (fundamentalType) { case FUNDTYPE.FT_U1: case FUNDTYPE.FT_U2: case FUNDTYPE.FT_U4: case FUNDTYPE.FT_U8: psz = ((ulong)((ExprConstant)const).Int64Value).ToString((IFormatProvider)CultureInfo.InvariantCulture); break; case FUNDTYPE.FT_I1: case FUNDTYPE.FT_I2: case FUNDTYPE.FT_I4: case FUNDTYPE.FT_I8: psz = ((ExprConstant)const).Int64Value.ToString(CultureInfo.InvariantCulture); break; default: val = ((ExprConstant)const).Val; psz = val.DoubleVal.ToString(CultureInfo.InvariantCulture); break; } throw ErrorHandling.Error(ErrorCode.ERR_ConstOutOfRangeChecked, psz, dest); } } if (expr.Type is NullType && dest.FundamentalType != FUNDTYPE.FT_REF) throw ErrorHandling.Error(ErrorCode.ERR_ValueCantBeNull, dest); throw CantConvert(expr, dest); } private static RuntimeBinderException CantConvert(Expr expr, CType dest) { return ErrorHandling.Error(ErrorCode.ERR_NoExplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique)); } public Expr mustCast(Expr expr, CType dest) { return mustCast(expr, dest, (CONVERTTYPE)0); } public Expr mustCast(Expr expr, CType dest, CONVERTTYPE flags) { return mustCastCore(expr, dest, flags); } private Expr MustCastInUncheckedContext(Expr expr, CType dest, CONVERTTYPE flags) { return new ExpressionBinder(new BindingContext(Context)).mustCast(expr, dest, flags); } private bool canCast(CType src, CType dest, CONVERTTYPE flags) { return BindExplicitConversion(null, src, dest, flags); } private bool BindImplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, CONVERTTYPE flags) { ImplicitConversion implicitConversion = new ImplicitConversion(this, pSourceExpr, pSourceType, destinationType, false, flags); return implicitConversion.Bind(); } private bool BindImplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, out Expr ppDestinationExpr, CONVERTTYPE flags) { ImplicitConversion implicitConversion = new ImplicitConversion(this, pSourceExpr, pSourceType, destinationType, true, flags); bool result = implicitConversion.Bind(); ppDestinationExpr = implicitConversion.ExprDest; return result; } private bool BindImplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, bool needsExprDest, out Expr ppDestinationExpr, CONVERTTYPE flags) { ImplicitConversion implicitConversion = new ImplicitConversion(this, pSourceExpr, pSourceType, destinationType, needsExprDest, flags); bool result = implicitConversion.Bind(); ppDestinationExpr = (needsExprDest ? implicitConversion.ExprDest : null); return result; } private bool BindExplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, bool needsExprDest, out Expr ppDestinationExpr, CONVERTTYPE flags) { ExplicitConversion explicitConversion = new ExplicitConversion(this, pSourceExpr, pSourceType, destinationType, needsExprDest, flags); bool result = explicitConversion.Bind(); ppDestinationExpr = (needsExprDest ? explicitConversion.ExprDest : null); return result; } private bool BindExplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, out Expr ppDestinationExpr, CONVERTTYPE flags) { ExplicitConversion explicitConversion = new ExplicitConversion(this, pSourceExpr, pSourceType, destinationType, true, flags); bool result = explicitConversion.Bind(); ppDestinationExpr = explicitConversion.ExprDest; return result; } private bool BindExplicitConversion(Expr pSourceExpr, CType pSourceType, CType destinationType, CONVERTTYPE flags) { ExplicitConversion explicitConversion = new ExplicitConversion(this, pSourceExpr, pSourceType, destinationType, false, flags); return explicitConversion.Bind(); } private bool bindUserDefinedConversion(Expr exprSrc, CType typeSrc, CType typeDst, bool needExprDest, out Expr pexprDst, bool fImplicitOnly) { pexprDst = null; if (typeSrc == null || typeDst == null || typeSrc.IsInterfaceType || typeDst.IsInterfaceType) return false; CType cType = typeSrc.StripNubs(); CType cType2 = typeDst.StripNubs(); bool flag = cType != typeSrc; bool flag2 = cType2 != typeDst; bool flag3 = flag2 || typeDst.IsReferenceType || typeDst is PointerType; AggregateType[] array = new AggregateType[2]; int num = 0; bool flag4 = fImplicitOnly; bool flag5 = false; AggregateType aggregateType = cType as AggregateType; if (aggregateType != null && aggregateType.OwningAggregate.HasConversion()) { array[num++] = aggregateType; flag5 = (aggregateType.IsPredefType(PredefinedType.FirstNonSimpleType) || aggregateType.IsPredefType(PredefinedType.PT_UINTPTR)); } AggregateType aggregateType2 = cType2 as AggregateType; if (aggregateType2 != null) { if (aggregateType2.OwningAggregate.HasConversion()) array[num++] = aggregateType2; if (flag5 && !cType2.IsPredefType(PredefinedType.PT_LONG) && !cType2.IsPredefType(PredefinedType.PT_ULONG)) flag5 = false; } else flag5 = false; if (num == 0) return false; List<UdConvInfo> list = new List<UdConvInfo>(); CType cType3 = null; CType cType4 = null; bool flag6 = false; bool flag7 = false; int num4 = -1; int num5 = -1; CType cType5; CType cType6; for (int i = 0; i < num; i++) { AggregateType aggregateType3 = array[i]; while (aggregateType3 != null && aggregateType3.OwningAggregate.HasConversion()) { AggregateSymbol owningAggregate = aggregateType3.OwningAggregate; PredefinedType predefType = owningAggregate.GetPredefType(); bool flag8 = owningAggregate.IsPredefined() && (predefType == PredefinedType.FirstNonSimpleType || predefType == PredefinedType.PT_UINTPTR || predefType == PredefinedType.PT_DECIMAL); for (MethodSymbol methodSymbol = owningAggregate.GetFirstUDConversion(); methodSymbol != null; methodSymbol = methodSymbol.ConvNext()) { if (methodSymbol.Params.Count == 1 && (!fImplicitOnly || methodSymbol.isImplicit())) { cType5 = TypeManager.SubstType(methodSymbol.Params[0], aggregateType3); cType6 = TypeManager.SubstType(methodSymbol.RetType, aggregateType3); bool flag9 = fImplicitOnly; if (flag4 && !flag9 && cType5.StripNubs() != cType) { if (!methodSymbol.isImplicit()) continue; flag9 = true; } FUNDTYPE fundamentalType2; FUNDTYPE fundamentalType; if (((fundamentalType = cType6.FundamentalType) > FUNDTYPE.FT_R8 || fundamentalType <= FUNDTYPE.FT_NONE || (fundamentalType2 = cType5.FundamentalType) > FUNDTYPE.FT_R8 || fundamentalType2 <= FUNDTYPE.FT_NONE) && (!flag5 || (!cType6.IsPredefType(PredefinedType.PT_INT) && !cType6.IsPredefType(PredefinedType.PT_UINT)))) { if (flag && (flag3 || !flag9) && cType5.IsNonNullableValueType) cType5 = TypeManager.GetNullable(cType5); if (flag2 && cType6.IsNonNullableValueType) cType6 = TypeManager.GetNullable(cType6); bool flag10 = (exprSrc != null) ? canConvert(exprSrc, cType5, CONVERTTYPE.STANDARDANDNOUDC) : canConvert(typeSrc, cType5, CONVERTTYPE.STANDARDANDNOUDC); if (flag10 || (!flag9 && (canConvert(cType5, typeSrc, CONVERTTYPE.STANDARDANDNOUDC) || (flag8 && !(typeSrc is PointerType) && !(cType5 is PointerType) && canCast(typeSrc, cType5, CONVERTTYPE.NOUDC))))) { bool flag11 = canConvert(cType6, typeDst, CONVERTTYPE.STANDARDANDNOUDC); if ((flag11 || (!flag9 && (canConvert(typeDst, cType6, CONVERTTYPE.STANDARDANDNOUDC) || (flag8 && !(typeDst is PointerType) && !(cType6 is PointerType) && canCast(cType6, typeDst, CONVERTTYPE.NOUDC))))) && !IsConvInTable(list, methodSymbol, aggregateType3, flag10, flag11)) { list.Add(new UdConvInfo(new MethWithType(methodSymbol, aggregateType3), flag10, flag11)); if (!flag6) { if (cType5 == typeSrc) { cType3 = cType5; num4 = list.Count - 1; flag6 = true; } else if (cType3 == null) { cType3 = cType5; num4 = list.Count - 1; } else if (cType3 != cType5) { int num6 = CompareSrcTypesBased(cType3, list[num4].SrcImplicit, cType5, flag10); if (num6 > 0) { cType3 = cType5; num4 = list.Count - 1; } } } if (!flag7) { if (cType6 == typeDst) { cType4 = cType6; num5 = list.Count - 1; flag7 = true; } else if (cType4 == null) { cType4 = cType6; num5 = list.Count - 1; } else if (cType4 != cType6) { int num7 = CompareDstTypesBased(cType4, list[num5].DstImplicit, cType6, flag11); if (num7 > 0) { cType4 = cType6; num5 = list.Count - 1; } } } } } } } } aggregateType3 = aggregateType3.BaseClass; } } if (cType3 == null) return false; int num8 = 3; int num9 = -1; int num10 = -1; for (int j = 0; j < list.Count; j++) { UdConvInfo udConvInfo = list[j]; cType5 = TypeManager.SubstType(udConvInfo.Meth.Meth().Params[0], udConvInfo.Meth.GetType()); cType6 = TypeManager.SubstType(udConvInfo.Meth.Meth().RetType, udConvInfo.Meth.GetType()); int num11 = 0; if (flag && cType5.IsNonNullableValueType) { cType5 = TypeManager.GetNullable(cType5); num11++; } if (flag2 && cType6.IsNonNullableValueType) { cType6 = TypeManager.GetNullable(cType6); num11++; } if (cType5 == cType3 && cType6 == cType4) { if (num8 > num11) { num9 = j; num10 = -1; num8 = num11; } else if (num8 >= num11 && num10 < 0) { num10 = j; if (num11 == 0) break; } } else { if (!flag6 && cType5 != cType3) { int num12 = CompareSrcTypesBased(cType3, list[num4].SrcImplicit, cType5, udConvInfo.SrcImplicit); if (num12 >= 0) { if (needExprDest) throw HandleAmbiguity(typeSrc, typeDst, list, num4, j); return true; } } if (!flag7 && cType6 != cType4) { int num13 = CompareDstTypesBased(cType4, list[num5].DstImplicit, cType6, udConvInfo.DstImplicit); if (num13 >= 0) { if (needExprDest) throw HandleAmbiguity(typeSrc, typeDst, list, num4, j); return true; } } } } if (!needExprDest) return true; if (num9 < 0) throw HandleAmbiguity(typeSrc, typeDst, list, num4, num5); if (num10 >= 0) throw HandleAmbiguity(typeSrc, typeDst, list, num9, num10); MethWithInst methWithInst = new MethWithInst(list[num9].Meth.Meth(), list[num9].Meth.GetType(), null); cType5 = TypeManager.SubstType(methWithInst.Meth().Params[0], methWithInst.GetType()); cType6 = TypeManager.SubstType(methWithInst.Meth().RetType, methWithInst.GetType()); Expr ppTransformedArgument = exprSrc; Expr call; if ((num8 > 0 && !(cType5 is NullableType)) & flag3) { ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, methWithInst); ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, typeDst, exprSrc, memberGroup, methWithInst); call = exprCall; Expr expr = mustCast(exprSrc, cType5); MarkAsIntermediateConversion(expr); Expr expr2 = BindUDConversionCore(expr, cType5, cType6, typeDst, methWithInst); exprCall.CastOfNonLiftedResultToLiftedType = mustCast(expr2, typeDst); exprCall.NullableCallLiftKind = NullableCallLiftKind.UserDefinedConversion; if (flag) { Expr expr3; if (cType5 == cType) expr3 = ((!(cType6 is NullableType)) ? exprSrc : mustCast(exprSrc, cType5)); else { NullableType nullable = TypeManager.GetNullable(cType5); expr3 = mustCast(exprSrc, nullable); MarkAsIntermediateConversion(expr3); } ExprCall exprCall2 = ExprFactory.CreateCall((EXPRFLAG)0, typeDst, expr3, memberGroup, methWithInst); exprCall2.NullableCallLiftKind = NullableCallLiftKind.NotLiftedIntermediateConversion; exprCall.PConversions = exprCall2; } else { Expr expr4 = BindUDConversionCore(expr, cType5, cType6, typeDst, methWithInst); MarkAsIntermediateConversion(expr4); exprCall.PConversions = expr4; } } else call = BindUDConversionCore(exprSrc, cType5, cType6, typeDst, methWithInst, out ppTransformedArgument); pexprDst = ExprFactory.CreateUserDefinedConversion(ppTransformedArgument, call, methWithInst); return true; } private static RuntimeBinderException HandleAmbiguity(CType typeSrc, CType typeDst, List<UdConvInfo> prguci, int iuciBestSrc, int iuciBestDst) { return ErrorHandling.Error(ErrorCode.ERR_AmbigUDConv, prguci[iuciBestSrc].Meth, prguci[iuciBestDst].Meth, typeSrc, typeDst); } private static void MarkAsIntermediateConversion(Expr pExpr) { while (true) { ExprCall exprCall = pExpr as ExprCall; if (exprCall != null) { switch (exprCall.NullableCallLiftKind) { default: return; case NullableCallLiftKind.NotLifted: exprCall.NullableCallLiftKind = NullableCallLiftKind.NotLiftedIntermediateConversion; return; case NullableCallLiftKind.NullableConversion: exprCall.NullableCallLiftKind = NullableCallLiftKind.NullableIntermediateConversion; return; case NullableCallLiftKind.NullableConversionConstructor: break; } pExpr = exprCall.OptionalArguments; } else { ExprUserDefinedConversion exprUserDefinedConversion = pExpr as ExprUserDefinedConversion; if (exprUserDefinedConversion == null) break; pExpr = exprUserDefinedConversion.UserDefinedCall; } } } private Expr BindUDConversionCore(Expr pFrom, CType pTypeFrom, CType pTypeTo, CType pTypeDestination, MethWithInst mwiBest) { Expr ppTransformedArgument; return BindUDConversionCore(pFrom, pTypeFrom, pTypeTo, pTypeDestination, mwiBest, out ppTransformedArgument); } private Expr BindUDConversionCore(Expr pFrom, CType pTypeFrom, CType pTypeTo, CType pTypeDestination, MethWithInst mwiBest, out Expr ppTransformedArgument) { Expr expr = mustCastCore(pFrom, pTypeFrom, CONVERTTYPE.NOUDC); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, mwiBest); ExprCall expr2 = ExprFactory.CreateCall((EXPRFLAG)0, pTypeTo, expr, memberGroup, mwiBest); Expr result = mustCastCore(expr2, pTypeDestination, CONVERTTYPE.NOUDC); ppTransformedArgument = expr; return result; } private ConstCastResult bindConstantCast(Expr exprSrc, CType typeDest, bool needExprDest, out Expr pexprDest, bool explicitConversion) { pexprDest = null; long num = 0; double num2 = 0; FUNDTYPE fundamentalType = exprSrc.Type.FundamentalType; FUNDTYPE fundamentalType2 = typeDest.FundamentalType; bool flag = fundamentalType <= FUNDTYPE.FT_U8; bool flag2 = fundamentalType <= FUNDTYPE.FT_R8; ExprConstant exprConstant = (ExprConstant)exprSrc.GetConst(); if (fundamentalType == FUNDTYPE.FT_STRUCT || fundamentalType2 == FUNDTYPE.FT_STRUCT) { Expr expr = BindDecimalConstCast(typeDest, exprSrc.Type, exprConstant); if (expr == null) { if (explicitConversion) return ConstCastResult.CheckFailure; return ConstCastResult.Failure; } if (needExprDest) pexprDest = expr; return ConstCastResult.Success; } if (explicitConversion && Context.Checked && !isConstantInRange(exprConstant, typeDest, true)) return ConstCastResult.CheckFailure; if (!needExprDest) return ConstCastResult.Success; if (flag) { if (exprConstant.Type.FundamentalType == FUNDTYPE.FT_U8) { if (fundamentalType2 == FUNDTYPE.FT_U8) { ConstVal constVal = ConstVal.Get(exprConstant.UInt64Value); pexprDest = ExprFactory.CreateConstant(typeDest, constVal); return ConstCastResult.Success; } num = ((long)exprConstant.UInt64Value & -1); } else num = exprConstant.Int64Value; } else { if (!flag2) return ConstCastResult.Failure; num2 = exprConstant.Val.DoubleVal; } switch (fundamentalType2) { case FUNDTYPE.FT_I1: if (!flag) num = (long)num2; num = (sbyte)(num & 255); break; case FUNDTYPE.FT_I2: if (!flag) num = (long)num2; num = (short)(num & 65535); break; case FUNDTYPE.FT_I4: if (!flag) num = (long)num2; num = (int)(num & uint.MaxValue); break; case FUNDTYPE.FT_I8: if (!flag) num = (long)num2; break; case FUNDTYPE.FT_U1: if (!flag) num = (long)num2; num = (byte)(num & 255); break; case FUNDTYPE.FT_U2: if (!flag) num = (long)num2; num = (ushort)(num & 65535); break; case FUNDTYPE.FT_U4: if (!flag) num = (long)num2; num = (uint)(num & uint.MaxValue); break; case FUNDTYPE.FT_U8: if (!flag) { num = (long)(ulong)num2; num = ((!(num2 < 9.223372036854776E+18)) ? ((long)(num2 - 9.223372036854776E+18) + I64(9223372036854775808)) : ((long)num2)); } break; case FUNDTYPE.FT_R4: case FUNDTYPE.FT_R8: if (flag) num2 = ((fundamentalType != FUNDTYPE.FT_U8) ? ((double)num) : ((double)(ulong)num)); if (fundamentalType2 == FUNDTYPE.FT_R4) { RoundToFloat(num2, out float f); num2 = (double)f; } break; } ConstVal constVal2 = (fundamentalType2 == FUNDTYPE.FT_U4) ? ConstVal.Get((uint)num) : ((fundamentalType2 <= FUNDTYPE.FT_U4) ? ConstVal.Get((int)num) : ((fundamentalType2 > FUNDTYPE.FT_U8) ? ConstVal.Get(num2) : ConstVal.Get(num))); ExprConstant exprConstant2 = (ExprConstant)(pexprDest = ExprFactory.CreateConstant(typeDest, constVal2)); return ConstCastResult.Success; } private int CompareSrcTypesBased(CType type1, bool fImplicit1, CType type2, bool fImplicit2) { if (fImplicit1 != fImplicit2) { if (!fImplicit1) return 1; return -1; } bool flag = canConvert(type1, type2, CONVERTTYPE.NOUDC); bool flag2 = canConvert(type2, type1, CONVERTTYPE.NOUDC); if (flag == flag2) return 0; if (fImplicit1 != flag) return 1; return -1; } private int CompareDstTypesBased(CType type1, bool fImplicit1, CType type2, bool fImplicit2) { if (fImplicit1 != fImplicit2) { if (!fImplicit1) return 1; return -1; } bool flag = canConvert(type1, type2, CONVERTTYPE.NOUDC); bool flag2 = canConvert(type2, type1, CONVERTTYPE.NOUDC); if (flag == flag2) return 0; if (fImplicit1 != flag) return -1; return 1; } private static Expr BindDecimalConstCast(CType destType, CType srcType, ExprConstant src) { CType predefindType = SymbolLoader.GetPredefindType(PredefinedType.PT_DECIMAL); if (predefindType == null) return null; ConstVal val; if (destType == predefindType) { decimal value; switch (srcType.FundamentalType) { case FUNDTYPE.FT_I1: case FUNDTYPE.FT_I2: case FUNDTYPE.FT_I4: val = src.Val; value = Convert.ToDecimal(val.Int32Val); break; case FUNDTYPE.FT_U1: case FUNDTYPE.FT_U2: case FUNDTYPE.FT_U4: val = src.Val; value = Convert.ToDecimal(val.UInt32Val); break; case FUNDTYPE.FT_R4: val = src.Val; value = Convert.ToDecimal((float)val.DoubleVal); break; case FUNDTYPE.FT_R8: val = src.Val; value = Convert.ToDecimal(val.DoubleVal); break; case FUNDTYPE.FT_U8: val = src.Val; value = Convert.ToDecimal((ulong)val.Int64Val); break; case FUNDTYPE.FT_I8: val = src.Val; value = Convert.ToDecimal(val.Int64Val); break; default: return null; } ConstVal constVal = ConstVal.Get(value); return ExprFactory.CreateConstant(predefindType, constVal); } if (srcType == predefindType) { decimal value2 = default(decimal); FUNDTYPE fundamentalType = destType.FundamentalType; ConstVal constVal; try { if (fundamentalType != FUNDTYPE.FT_R4 && fundamentalType != FUNDTYPE.FT_R8) { val = src.Val; value2 = decimal.Truncate(val.DecimalVal); } switch (fundamentalType) { case FUNDTYPE.FT_I1: constVal = ConstVal.Get(Convert.ToSByte(value2)); break; case FUNDTYPE.FT_U1: constVal = ConstVal.Get((uint)Convert.ToByte(value2)); break; case FUNDTYPE.FT_I2: constVal = ConstVal.Get(Convert.ToInt16(value2)); break; case FUNDTYPE.FT_U2: constVal = ConstVal.Get((uint)Convert.ToUInt16(value2)); break; case FUNDTYPE.FT_I4: constVal = ConstVal.Get(Convert.ToInt32(value2)); break; case FUNDTYPE.FT_U4: constVal = ConstVal.Get(Convert.ToUInt32(value2)); break; case FUNDTYPE.FT_I8: constVal = ConstVal.Get(Convert.ToInt64(value2)); break; case FUNDTYPE.FT_U8: constVal = ConstVal.Get(Convert.ToUInt64(value2)); break; case FUNDTYPE.FT_R4: val = src.Val; constVal = ConstVal.Get(Convert.ToSingle(val.DecimalVal)); break; case FUNDTYPE.FT_R8: val = src.Val; constVal = ConstVal.Get(Convert.ToDouble(val.DecimalVal)); break; default: return null; } } catch (OverflowException) { return null; } return ExprFactory.CreateConstant(destType, constVal); } return null; } private bool CanExplicitConversionBeBoundInUncheckedContext(Expr exprSrc, CType typeSrc, CType typeDest, CONVERTTYPE flags) { return new ExpressionBinder(new BindingContext(Context)).BindExplicitConversion(exprSrc, typeSrc, typeDest, flags); } public ExpressionBinder(BindingContext context) { Context = context; } private static AggregateType GetPredefindType(PredefinedType pt) { return SymbolLoader.GetPredefindType(pt); } private Expr GenerateAssignmentConversion(Expr op1, Expr op2, bool allowExplicit) { if (!allowExplicit) return mustConvertCore(op2, op1.Type); return mustCastCore(op2, op1.Type, (CONVERTTYPE)0); } public Expr BindAssignment(Expr op1, Expr op2, bool allowExplicit) { CheckLvalue(op1, CheckLvalueKind.Assignment); op2 = GenerateAssignmentConversion(op1, op2, allowExplicit); return GenerateOptimizedAssignment(op1, op2); } internal Expr BindArrayIndexCore(Expr pOp1, Expr pOp2) { CType pIntType = GetPredefindType(PredefinedType.PT_INT); ArrayType arrayType = pOp1.Type as ArrayType; CType elementType = arrayType.ElementType; CheckUnsafe(elementType); CType pDestType = ChooseArrayIndexType(pOp2); ExpressionBinder binder = this; Expr index = pOp2.Map(delegate(Expr x) { Expr expr = binder.mustConvert(x, pDestType); if (pDestType != pIntType) return ExprFactory.CreateCast(EXPRFLAG.EXF_LITERALCONST, pDestType, expr); return expr; }); return ExprFactory.CreateArrayIndex(elementType, pOp1, index); } private void bindSimpleCast(Expr exprSrc, CType typeDest, out Expr pexprDest) { bindSimpleCast(exprSrc, typeDest, out pexprDest, (EXPRFLAG)0); } private void bindSimpleCast(Expr exprSrc, CType typeDest, out Expr pexprDest, EXPRFLAG exprFlags) { Expr const = exprSrc.GetConst(); ExprCast exprCast = ExprFactory.CreateCast(exprFlags, typeDest, exprSrc); if (Context.Checked) exprCast.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW; ExprConstant exprConstant = const as ExprConstant; if (exprConstant != null && exprFlags == (EXPRFLAG)0 && exprSrc.Type.FundamentalType == typeDest.FundamentalType && (!exprSrc.Type.IsPredefType(PredefinedType.PT_STRING) || exprConstant.Val.IsNullRef)) { ExprConstant exprConstant2 = (ExprConstant)(pexprDest = ExprFactory.CreateConstant(typeDest, exprConstant.Val)); } else pexprDest = exprCast; } private ExprCall BindToMethod(MethWithInst mwi, Expr pArguments, ExprMemberGroup pMemGroup, MemLookFlags flags) { Expr optionalObject = pMemGroup.OptionalObject; CType callingObjectType = optionalObject?.Type; PostBindMethod(mwi); optionalObject = (pMemGroup.OptionalObject = AdjustMemberObject(mwi, optionalObject)); CType type = ((flags & (MemLookFlags.Ctor | MemLookFlags.NewObj)) != (MemLookFlags.Ctor | MemLookFlags.NewObj)) ? TypeManager.SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs) : mwi.Ats; ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, type, pArguments, pMemGroup, mwi); if ((flags & MemLookFlags.Ctor) != 0 && (flags & MemLookFlags.NewObj) != 0) exprCall.Flags |= (EXPRFLAG.EXF_LITERALCONST | EXPRFLAG.EXF_CANTBENULL); verifyMethodArgs(exprCall, callingObjectType); return exprCall; } internal Expr BindToField(Expr pOptionalObject, FieldWithType fwt, BindingFlag bindFlags) { CType cType = TypeManager.SubstType(fwt.Field().GetType(), fwt.GetType()); pOptionalObject = AdjustMemberObject(fwt, pOptionalObject); CheckUnsafe(cType); AggregateType aggregateType = null; if (fwt.Field().isEvent && fwt.Field().getEvent() != null && fwt.Field().getEvent().IsWindowsRuntimeEvent) { aggregateType = (fwt.Field().GetType() as AggregateType); if (aggregateType != null) cType = TypeManager.GetParameterModifier(cType, false); } ExprField exprField = ExprFactory.CreateField(cType, pOptionalObject, fwt); exprField.Flags |= (EXPRFLAG)(bindFlags & BindingFlag.BIND_MEMBERSET); if (aggregateType != null) { Name predefinedName = NameManager.GetPredefinedName(PredefinedName.PN_GETORCREATEEVENTREGISTRATIONTOKENTABLE); SymbolTable.PopulateSymbolTableWithName(predefinedName.Text, null, aggregateType.AssociatedSystemType); MethodSymbol mps = SymbolLoader.LookupAggMember(predefinedName, aggregateType.OwningAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol; MethPropWithInst methPropWithInst = new MethPropWithInst(mps, aggregateType); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, methPropWithInst); Expr expr = BindToMethod(new MethWithInst(methPropWithInst), exprField, pMemGroup, MemLookFlags.None); AggregateSymbol owningAggregate = aggregateType.OwningAggregate; Name predefinedName2 = NameManager.GetPredefinedName(PredefinedName.PN_INVOCATIONLIST); SymbolTable.PopulateSymbolTableWithName(predefinedName2.Text, null, aggregateType.AssociatedSystemType); PropertySymbol propertySymbol = SymbolLoader.LookupAggMember(predefinedName2, owningAggregate, symbmask_t.MASK_PropertySymbol) as PropertySymbol; MethPropWithInst method = new MethPropWithInst(propertySymbol, aggregateType); ExprMemberGroup pMemGroup2 = ExprFactory.CreateMemGroup(expr, method); PropWithType pwt = new PropWithType(propertySymbol, aggregateType); return BindToProperty(expr, pwt, bindFlags, null, pMemGroup2); } return exprField; } internal ExprProperty BindToProperty(Expr pObject, PropWithType pwt, BindingFlag bindFlags, Expr args, ExprMemberGroup pMemGroup) { Expr expr = pObject; PostBindProperty(pwt, out MethWithType pmwtGet, out MethWithType pmwtSet); pObject = (((bool)pmwtGet && (!(bool)pmwtSet || pmwtSet.GetType() == pmwtGet.GetType() || SymbolLoader.HasBaseConversion(pmwtGet.GetType(), pmwtSet.GetType()))) ? AdjustMemberObject(pmwtGet, pObject) : ((!(bool)pmwtSet) ? AdjustMemberObject(pwt, pObject) : AdjustMemberObject(pmwtSet, pObject))); pMemGroup.OptionalObject = pObject; CType type = TypeManager.SubstType(pwt.Prop().RetType, pwt.GetType()); if ((bindFlags & BindingFlag.BIND_RVALUEREQUIRED) != 0) { if (!(bool)pmwtGet) throw ErrorHandling.Error(ErrorCode.ERR_PropertyLacksGet, pwt); CType cType = null; if (expr != null) cType = expr.Type; switch (CSemanticChecker.CheckAccess2(pmwtGet.Meth(), pmwtGet.GetType(), ContextForMemberLookup, cType)) { case ACCESSERROR.ACCESSERROR_NOACCESSTHRU: throw ErrorHandling.Error(ErrorCode.ERR_BadProtectedAccess, pwt, cType, ContextForMemberLookup); default: throw ErrorHandling.Error(ErrorCode.ERR_InaccessibleGetter, pwt); case ACCESSERROR.ACCESSERROR_NOERROR: break; } } ExprProperty exprProperty = ExprFactory.CreateProperty(type, expr, args, pMemGroup, pwt, pmwtSet); if (exprProperty.OptionalArguments != null) verifyMethodArgs(exprProperty, expr?.Type); return exprProperty; } internal Expr bindUDUnop(ExpressionKind ek, Expr arg) { Name name = ExpressionKindName(ek); CType cType = arg.Type; while (true) { switch (cType.TypeKind) { case TypeKind.TK_NullableType: break; case TypeKind.TK_AggregateType: { if ((!cType.IsClassType && !cType.IsStructType) || ((AggregateType)cType).OwningAggregate.IsSkipUDOps()) return null; ArgInfos argInfos = new ArgInfos(); argInfos.carg = 1; FillInArgInfoFromArgList(argInfos, arg); List<CandidateFunctionMember> list = new List<CandidateFunctionMember>(); MethodSymbol methodSymbol = null; AggregateType aggregateType = (AggregateType)cType; while (true) { methodSymbol = (((methodSymbol == null) ? SymbolLoader.LookupAggMember(name, aggregateType.OwningAggregate, symbmask_t.MASK_MethodSymbol) : methodSymbol.LookupNext(symbmask_t.MASK_MethodSymbol)) as MethodSymbol); if (methodSymbol == null) { if (!list.IsEmpty()) break; aggregateType = aggregateType.BaseClass; if (aggregateType == null) break; } else if (methodSymbol.isOperator && methodSymbol.Params.Count == 1) { TypeArray typeArray = TypeManager.SubstTypeArray(methodSymbol.Params, aggregateType); CType cType2 = typeArray[0]; NullableType nullable; if (canConvert(arg, cType2)) list.Add(new CandidateFunctionMember(new MethPropWithInst(methodSymbol, aggregateType, TypeArray.Empty), typeArray, 0, false)); else if (cType2.IsNonNullableValueType && TypeManager.SubstType(methodSymbol.RetType, aggregateType).IsNonNullableValueType && canConvert(arg, nullable = TypeManager.GetNullable(cType2))) { list.Add(new CandidateFunctionMember(new MethPropWithInst(methodSymbol, aggregateType, TypeArray.Empty), TypeArray.Allocate(nullable), 1, false)); } } } if (list.IsEmpty()) return null; CandidateFunctionMember methAmbig; CandidateFunctionMember methAmbig2; CandidateFunctionMember candidateFunctionMember = FindBestMethod(list, null, argInfos, out methAmbig, out methAmbig2); if (candidateFunctionMember == null) throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, methAmbig.mpwi, methAmbig2.mpwi); ExprCall exprCall = (candidateFunctionMember.ctypeLift == 0) ? BindUDUnopCall(arg, candidateFunctionMember.params[0], candidateFunctionMember.mpwi) : BindLiftedUDUnop(arg, candidateFunctionMember.params[0], candidateFunctionMember.mpwi); return ExprFactory.CreateUserDefinedUnaryOperator(ek, exprCall.Type, arg, exprCall, candidateFunctionMember.mpwi); } default: return null; } cType = cType.StripNubs(); } } private ExprCall BindLiftedUDUnop(Expr arg, CType typeArg, MethPropWithInst mpwi) { CType cType = typeArg.StripNubs(); if (!(arg.Type is NullableType) || !canConvert(arg.Type.StripNubs(), cType, CONVERTTYPE.NOUDC)) arg = mustConvert(arg, typeArg); CType cType2 = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType()); if (!(cType2 is NullableType)) cType2 = TypeManager.GetNullable(cType2); Expr arg2 = mustCast(arg, cType); ExprCall expr = BindUDUnopCall(arg2, cType, mpwi); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, mpwi); ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, cType2, arg, memberGroup, null); exprCall.MethWithInst = new MethWithInst(mpwi); exprCall.CastOfNonLiftedResultToLiftedType = mustCast(expr, cType2, (CONVERTTYPE)0); exprCall.NullableCallLiftKind = NullableCallLiftKind.Operator; return exprCall; } private ExprCall BindUDUnopCall(Expr arg, CType typeArg, MethPropWithInst mpwi) { CType type = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType()); CheckUnsafe(type); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, mpwi); ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, type, mustConvert(arg, typeArg), memberGroup, null); exprCall.MethWithInst = new MethWithInst(mpwi); verifyMethodArgs(exprCall, mpwi.GetType()); return exprCall; } private GroupToArgsBinderResult BindMethodGroupToArgumentsCore(BindingFlag bindFlags, ExprMemberGroup grp, Expr args, int carg, NamedArgumentsKind namedArgumentsKind) { ArgInfos argInfos = new ArgInfos { carg = carg }; FillInArgInfoFromArgList(argInfos, args); ArgInfos argInfos2 = new ArgInfos { carg = carg }; FillInArgInfoFromArgList(argInfos2, args); GroupToArgsBinder groupToArgsBinder = new GroupToArgsBinder(this, bindFlags, grp, argInfos, argInfos2, namedArgumentsKind); groupToArgsBinder.Bind(); return groupToArgsBinder.GetResultsOfBind(); } internal ExprWithArgs BindMethodGroupToArguments(BindingFlag bindFlags, ExprMemberGroup grp, Expr args) { int carg = CountArguments(args); NamedArgumentsKind namedArgumentsKind = FindNamedArgumentsType(args); MethPropWithInst bestResult = BindMethodGroupToArgumentsCore(bindFlags, grp, args, carg, namedArgumentsKind).BestResult; if (grp.SymKind == SYMKIND.SK_PropertySymbol) return BindToProperty(grp.OptionalObject, new PropWithType(bestResult), bindFlags, args, grp); return BindToMethod(new MethWithInst(bestResult), args, grp, (MemLookFlags)grp.Flags); } private static NamedArgumentsKind FindNamedArgumentsType(Expr args) { Expr expr = args; while (expr != null) { ExprList exprList = expr as ExprList; Expr expr2; if (exprList != null) { expr2 = exprList.OptionalElement; expr = exprList.OptionalNextListNode; } else { expr2 = expr; expr = null; } if (expr2 is ExprNamedArgumentSpecification) { while (expr != null) { ExprList exprList2 = expr as ExprList; if (exprList2 != null) { expr2 = exprList2.OptionalElement; expr = exprList2.OptionalNextListNode; } else { expr2 = expr; expr = null; } if (!(expr2 is ExprNamedArgumentSpecification)) return NamedArgumentsKind.NonTrailing; } return NamedArgumentsKind.Positioning; } } return NamedArgumentsKind.None; } private static RuntimeBinderException BadOperatorTypesError(Expr pOperand1, Expr pOperand2) { string errorString = pOperand1.ErrorString; if (pOperand2 != null) return ErrorHandling.Error(ErrorCode.ERR_BadBinaryOps, errorString, pOperand1.Type, pOperand2.Type); return ErrorHandling.Error(ErrorCode.ERR_BadUnaryOp, errorString, pOperand1.Type); } private static ErrorCode GetStandardLvalueError(CheckLvalueKind kind) { if (kind != CheckLvalueKind.Increment) return ErrorCode.ERR_AssgLvalueExpected; return ErrorCode.ERR_IncrementLvalueExpected; } private void CheckLvalueProp(ExprProperty prop) { CType type = null; if (prop.OptionalObjectThrough != null) type = prop.OptionalObjectThrough.Type; CheckPropertyAccess(prop.MethWithTypeSet, prop.PropWithTypeSlot, type); } private void CheckPropertyAccess(MethWithType mwt, PropWithType pwtSlot, CType type) { switch (CSemanticChecker.CheckAccess2(mwt.Meth(), mwt.GetType(), ContextForMemberLookup, type)) { case ACCESSERROR.ACCESSERROR_NOACCESSTHRU: throw ErrorHandling.Error(ErrorCode.ERR_BadProtectedAccess, pwtSlot, type, ContextForMemberLookup); case ACCESSERROR.ACCESSERROR_NOACCESS: throw ErrorHandling.Error(mwt.Meth().isSetAccessor() ? ErrorCode.ERR_InaccessibleSetter : ErrorCode.ERR_InaccessibleGetter, pwtSlot); } } private void CheckLvalue(Expr expr, CheckLvalueKind kind) { if (!expr.isLvalue()) { switch (expr.Kind) { case ExpressionKind.Property: { ExprProperty exprProperty = (ExprProperty)expr; throw ErrorHandling.Error(ErrorCode.ERR_AssgReadonlyProp, exprProperty.PropWithTypeSlot); } case ExpressionKind.Field: { ExprField exprField = (ExprField)expr; throw ErrorHandling.Error(exprField.FieldWithType.Field().isStatic ? ErrorCode.ERR_AssgReadonlyStatic : ErrorCode.ERR_AssgReadonly, Array.Empty<ErrArg>()); } default: throw ErrorHandling.Error(GetStandardLvalueError(kind), Array.Empty<ErrArg>()); } } ExprProperty exprProperty2 = expr as ExprProperty; if (exprProperty2 != null) CheckLvalueProp(exprProperty2); } private static void PostBindMethod(MethWithInst pMWI) { MethodSymbol methodSymbol = pMWI.Meth(); if (methodSymbol.RetType != null) { CheckUnsafe(methodSymbol.RetType); CType[] items = methodSymbol.Params.Items; foreach (CType type in items) { CheckUnsafe(type); } } } private static void PostBindProperty(PropWithType pwt, out MethWithType pmwtGet, out MethWithType pmwtSet) { PropertySymbol propertySymbol = pwt.Prop(); pmwtGet = ((propertySymbol.GetterMethod != null) ? new MethWithType(propertySymbol.GetterMethod, pwt.GetType()) : new MethWithType()); pmwtSet = ((propertySymbol.SetterMethod != null) ? new MethWithType(propertySymbol.SetterMethod, pwt.GetType()) : new MethWithType()); if (propertySymbol.RetType != null) CheckUnsafe(propertySymbol.RetType); } private Expr AdjustMemberObject(SymWithType swt, Expr pObject) { bool flag = IsMatchingStatic(swt, pObject); bool isStatic = swt.Sym.isStatic; if (!flag) { if (isStatic) { if ((pObject.Flags & EXPRFLAG.EXF_UNREALIZEDGOTO) != 0) return null; throw ErrorHandling.Error(ErrorCode.ERR_ObjectProhibited, swt); } throw ErrorHandling.Error(ErrorCode.ERR_ObjectRequired, swt); } if (isStatic) return null; if (swt.Sym is MethodSymbol && swt.Meth().IsConstructor()) return pObject; if (pObject == null) return null; CType cType = pObject.Type; NullableType nullableType = cType as NullableType; CType ats; if (nullableType != null && (ats = nullableType.GetAts()) != swt.GetType()) cType = ats; if (cType is TypeParameterType || cType is AggregateType) { AggregateSymbol aggregateSymbol = swt.Sym.parent as AggregateSymbol; pObject = tryConvert(pObject, swt.GetType(), CONVERTTYPE.NOUDC); } return pObject; } private static bool IsMatchingStatic(SymWithType swt, Expr pObject) { Symbol sym = swt.Sym; MethodSymbol methodSymbol = sym as MethodSymbol; if (methodSymbol != null && methodSymbol.IsConstructor()) return !methodSymbol.isStatic; if (swt.Sym.isStatic) { if (pObject == null) return true; if ((pObject.Flags & EXPRFLAG.EXF_SAMENAMETYPE) == (EXPRFLAG)0) return false; } else if (pObject == null) { return false; } return true; } private void verifyMethodArgs(ExprWithArgs call, CType callingObjectType) { Expr optionalArguments = call.OptionalArguments; SymWithType symWithType = call.GetSymWithType(); MethodOrPropertySymbol mp = symWithType.Sym as MethodOrPropertySymbol; TypeArray pTypeArgs = (call as ExprCall)?.MethWithInst.TypeArgs; AdjustCallArgumentsForParams(callingObjectType, symWithType.GetType(), mp, pTypeArgs, optionalArguments, out Expr newArgs); call.OptionalArguments = newArgs; } private void AdjustCallArgumentsForParams(CType callingObjectType, CType type, MethodOrPropertySymbol mp, TypeArray pTypeArgs, Expr argsPtr, out Expr newArgs) { newArgs = null; Expr last = null; MethodOrPropertySymbol methodOrPropertySymbol = GroupToArgsBinder.FindMostDerivedMethod(mp, callingObjectType); int num = mp.Params.Count; TypeArray params = mp.Params; int num2 = 0; MethodSymbol methodSymbol = mp as MethodSymbol; int num3 = ExpressionIterator.Count(argsPtr); bool flag = false; ExpressionIterator expressionIterator = new ExpressionIterator(argsPtr); if (argsPtr != null) { while (true) { if (expressionIterator.AtEnd()) return; Expr expr = expressionIterator.Current(); if (!(expr.Type is ParameterModifierType)) { switch (num) { case 1: break; default: goto IL_00a6; case 0: goto IL_0206; } if (mp.isParamArray && num3 > mp.Params.Count) break; goto IL_00a6; } if (num != 0) num--; ExprFactory.AppendItemToList(expr, ref newArgs, ref last); goto IL_0206; IL_0206: num2++; if (num != 0 && mp.isParamArray && num2 == num3) { expr = null; expressionIterator.MoveNext(); break; } expressionIterator.MoveNext(); continue; IL_00a6: Expr expr2 = expr; ExprNamedArgumentSpecification exprNamedArgumentSpecification = expr2 as ExprNamedArgumentSpecification; Expr expr3; if (exprNamedArgumentSpecification != null) { int num4 = 0; foreach (Name parameterName in methodOrPropertySymbol.ParameterNames) { if (parameterName == exprNamedArgumentSpecification.Name) break; num4++; } CType dest = TypeManager.SubstType(params[num4], type, pTypeArgs); if (!canConvert(exprNamedArgumentSpecification.Value, dest) && mp.isParamArray && num4 == mp.Params.Count - 1) { CType type2 = (ArrayType)TypeManager.SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs); ExprArrayInit exprArrayInit = ExprFactory.CreateArrayInit(type2, null, null, new int[1]); exprArrayInit.GeneratedForParamArray = true; exprArrayInit.OptionalArguments = exprNamedArgumentSpecification.Value; exprNamedArgumentSpecification.Value = exprArrayInit; flag = true; } else exprNamedArgumentSpecification.Value = tryConvert(exprNamedArgumentSpecification.Value, dest); expr3 = expr2; } else { CType dest2 = TypeManager.SubstType(params[num2], type, pTypeArgs); expr3 = tryConvert(expr, dest2); } if (expr3 == null) { if (mp.isParamArray && num == 1 && num3 >= mp.Params.Count) break; return; } expr = expr3; ExprFactory.AppendItemToList(expr3, ref newArgs, ref last); num--; goto IL_0206; } } else if (!mp.isParamArray) { return; } if (!flag) { CType cType = TypeManager.SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs); ArrayType arrayType = cType as ArrayType; if (arrayType != null && arrayType.IsSZArray) { CType elementType = arrayType.ElementType; ExprArrayInit exprArrayInit2 = ExprFactory.CreateArrayInit(cType, null, null, new int[1]); exprArrayInit2.GeneratedForParamArray = true; if (expressionIterator.AtEnd()) { exprArrayInit2.DimensionSizes[0] = 0; exprArrayInit2.OptionalArguments = null; argsPtr = ((argsPtr != null) ? ((Expr)ExprFactory.CreateList(argsPtr, exprArrayInit2)) : ((Expr)exprArrayInit2)); ExprFactory.AppendItemToList(exprArrayInit2, ref newArgs, ref last); } else { Expr first = null; Expr last2 = null; int num5 = 0; while (!expressionIterator.AtEnd()) { Expr expr4 = expressionIterator.Current(); num5++; ExprNamedArgumentSpecification exprNamedArgumentSpecification2 = expr4 as ExprNamedArgumentSpecification; if (exprNamedArgumentSpecification2 != null) exprNamedArgumentSpecification2.Value = tryConvert(exprNamedArgumentSpecification2.Value, elementType); else expr4 = tryConvert(expr4, elementType); ExprFactory.AppendItemToList(expr4, ref first, ref last2); expressionIterator.MoveNext(); } exprArrayInit2.DimensionSizes[0] = num5; exprArrayInit2.OptionalArguments = first; ExprFactory.AppendItemToList(exprArrayInit2, ref newArgs, ref last); } } } } internal CType ChooseArrayIndexType(Expr args) { PredefinedType[] array = s_rgptIntOp; foreach (PredefinedType pt in array) { CType predefindType = GetPredefindType(pt); using (IEnumerator<Expr> enumerator = args.ToEnumerable().GetEnumerator()) { Expr current; do { if (!enumerator.MoveNext()) return predefindType; current = enumerator.Current; } while (canConvert(current, predefindType)); } } return GetPredefindType(PredefinedType.PT_INT); } internal static void FillInArgInfoFromArgList(ArgInfos argInfo, Expr args) { CType[] array = new CType[argInfo.carg]; argInfo.prgexpr = new List<Expr>(); int num = 0; Expr expr = args; while (expr != null) { ExprList exprList = expr as ExprList; Expr expr2; if (exprList != null) { expr2 = exprList.OptionalElement; expr = exprList.OptionalNextListNode; } else { expr2 = expr; expr = null; } array[num] = expr2.Type; argInfo.prgexpr.Add(expr2); num++; } argInfo.types = TypeArray.Allocate(array); } private static bool TryGetExpandedParams(TypeArray params, int count, out TypeArray ppExpandedParams) { CType[] array; if (count < params.Count - 1) { array = new CType[params.Count - 1]; params.CopyItems(0, params.Count - 1, array); ppExpandedParams = TypeArray.Allocate(array); return true; } array = new CType[count]; params.CopyItems(0, params.Count - 1, array); CType cType = params[params.Count - 1]; ArrayType arrayType = cType as ArrayType; if (arrayType == null) { ppExpandedParams = null; return false; } CType elementType = arrayType.ElementType; for (int i = params.Count - 1; i < count; i++) { array[i] = elementType; } ppExpandedParams = TypeArray.Allocate(array); return true; } public static bool IsMethPropCallable(MethodOrPropertySymbol sym, bool requireUC) { if (!sym.isOverride || sym.isHideByName) { if (requireUC) return sym.isUserCallable(); return true; } return false; } private static bool IsConvInTable(List<UdConvInfo> convTable, MethodSymbol meth, AggregateType ats, bool fSrc, bool fDst) { foreach (UdConvInfo item in convTable) { if (item.Meth.Meth() == meth && item.Meth.GetType() == ats && item.SrcImplicit == fSrc && item.DstImplicit == fDst) return true; } return false; } private static bool isConstantInRange(ExprConstant exprSrc, CType typeDest) { return isConstantInRange(exprSrc, typeDest, false); } private static bool isConstantInRange(ExprConstant exprSrc, CType typeDest, bool realsOk) { FUNDTYPE fundamentalType = exprSrc.Type.FundamentalType; FUNDTYPE fundamentalType2 = typeDest.FundamentalType; if (fundamentalType > FUNDTYPE.FT_U8 || fundamentalType2 > FUNDTYPE.FT_U8) { if (!realsOk) return false; if (fundamentalType > FUNDTYPE.FT_R8 || fundamentalType2 > FUNDTYPE.FT_R8) return false; } if (fundamentalType2 > FUNDTYPE.FT_U8) return true; if (fundamentalType > FUNDTYPE.FT_U8) { double doubleVal = exprSrc.Val.DoubleVal; switch (fundamentalType2) { case FUNDTYPE.FT_I1: if (doubleVal > -129 && doubleVal < 128) return true; break; case FUNDTYPE.FT_I2: if (doubleVal > -32769 && doubleVal < 32768) return true; break; case FUNDTYPE.FT_I4: if (doubleVal > (double)I64(-2147483649) && doubleVal < (double)I64(2147483648)) return true; break; case FUNDTYPE.FT_I8: if (doubleVal >= -9.223372036854776E+18 && doubleVal < 9.223372036854776E+18) return true; break; case FUNDTYPE.FT_U1: if (doubleVal > -1 && doubleVal < 256) return true; break; case FUNDTYPE.FT_U2: if (doubleVal > -1 && doubleVal < 65536) return true; break; case FUNDTYPE.FT_U4: if (doubleVal > -1 && doubleVal < (double)I64(4294967296)) return true; break; case FUNDTYPE.FT_U8: if (doubleVal > -1 && doubleVal < 1.8446744073709552E+19) return true; break; } return false; } if (fundamentalType == FUNDTYPE.FT_U8) { ulong uInt64Value = exprSrc.UInt64Value; switch (fundamentalType2) { case FUNDTYPE.FT_I1: if (uInt64Value <= 127) return true; break; case FUNDTYPE.FT_I2: if (uInt64Value <= 32767) return true; break; case FUNDTYPE.FT_I4: if (uInt64Value <= 2147483647) return true; break; case FUNDTYPE.FT_I8: if (uInt64Value <= 9223372036854775807) return true; break; case FUNDTYPE.FT_U1: if (uInt64Value <= 255) return true; break; case FUNDTYPE.FT_U2: if (uInt64Value <= 65535) return true; break; case FUNDTYPE.FT_U4: if (uInt64Value <= uint.MaxValue) return true; break; case FUNDTYPE.FT_U8: return true; } } else { long int64Value = exprSrc.Int64Value; switch (fundamentalType2) { case FUNDTYPE.FT_I1: if (int64Value >= -128 && int64Value <= 127) return true; break; case FUNDTYPE.FT_I2: if (int64Value >= -32768 && int64Value <= 32767) return true; break; case FUNDTYPE.FT_I4: if (int64Value >= I64(-2147483648) && int64Value <= I64(2147483647)) return true; break; case FUNDTYPE.FT_I8: return true; case FUNDTYPE.FT_U1: if (int64Value >= 0 && int64Value <= 255) return true; break; case FUNDTYPE.FT_U2: if (int64Value >= 0 && int64Value <= 65535) return true; break; case FUNDTYPE.FT_U4: if (int64Value >= 0 && int64Value <= I64(4294967295)) return true; break; case FUNDTYPE.FT_U8: if (int64Value >= 0) return true; break; } } return false; } private static Name ExpressionKindName(ExpressionKind ek) { return NameManager.GetPredefinedName(s_EK2NAME[(int)(ek - 29)]); } private static void CheckUnsafe(CType type) { if (type == null || type.IsUnsafe()) throw ErrorHandling.Error(ErrorCode.ERR_UnsafeNeeded, Array.Empty<ErrArg>()); } private static ExprWrap WrapShortLivedExpression(Expr expr) { return ExprFactory.CreateWrap(expr); } private static ExprAssignment GenerateOptimizedAssignment(Expr op1, Expr op2) { return ExprFactory.CreateAssignment(op1, op2); } internal static int CountArguments(Expr args) { int num = 0; Expr expr = args; while (expr != null) { ExprList exprList = expr as ExprList; if (exprList != null) { Expr optionalElement = exprList.OptionalElement; expr = exprList.OptionalNextListNode; } else { Expr optionalElement = expr; expr = null; } num++; } return num; } private static bool IsNullableConstructor(Expr expr, out ExprCall call) { ExprCall exprCall = expr as ExprCall; if (exprCall != null && exprCall.MemberGroup.OptionalObject == null && (exprCall.MethWithInst?.Meth().IsNullableConstructor() ?? false)) { call = exprCall; return true; } call = null; return false; } private static Expr StripNullableConstructor(Expr pExpr) { ExprCall call; while (IsNullableConstructor(pExpr, out call)) { pExpr = call.OptionalArguments; } return pExpr; } private static Expr BindNubValue(Expr exprSrc) { if (IsNullableConstructor(exprSrc, out ExprCall call)) return call.OptionalArguments; NullableType nullableType = (NullableType)exprSrc.Type; CType underlyingType = nullableType.UnderlyingType; AggregateType ats = nullableType.GetAts(); PropertySymbol property = PredefinedMembers.GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE); PropWithType property2 = new PropWithType(property, ats); MethPropWithInst method = new MethPropWithInst(property, ats); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(exprSrc, method); return ExprFactory.CreateProperty(underlyingType, null, null, memberGroup, property2, null); } private static ExprCall BindNubNew(Expr exprSrc) { NullableType nullable = TypeManager.GetNullable(exprSrc.Type); AggregateType ats = nullable.GetAts(); MethodSymbol method = PredefinedMembers.GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); MethWithInst method2 = new MethWithInst(method, ats, TypeArray.Empty); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, method2); return ExprFactory.CreateCall(EXPRFLAG.EXF_LITERALCONST | EXPRFLAG.EXF_CANTBENULL, nullable, exprSrc, memberGroup, method2); } private ExprBinOp BindUserDefinedBinOp(ExpressionKind ek, BinOpArgInfo info) { if (info.pt1 <= PredefinedType.PT_ULONG && info.pt2 <= PredefinedType.PT_ULONG) return null; MethPropWithInst ppmpwi; Expr expr; if (info.binopKind == BinOpKind.Logical) { ExprCall exprCall = BindUDBinop(ek - 55 + 49, info.arg1, info.arg2, true, out ppmpwi); if (exprCall == null) return null; expr = BindUserBoolOp(ek, exprCall); } else expr = BindUDBinop(ek, info.arg1, info.arg2, false, out ppmpwi); if (expr == null) return null; return ExprFactory.CreateUserDefinedBinop(ek, expr.Type, info.arg1, info.arg2, expr, ppmpwi); } private bool GetSpecialBinopSignatures(List<BinOpFullSig> prgbofs, BinOpArgInfo info) { if (info.pt1 <= PredefinedType.PT_ULONG && info.pt2 <= PredefinedType.PT_ULONG) return false; if (!GetDelBinOpSigs(prgbofs, info) && !GetEnumBinOpSigs(prgbofs, info)) return GetRefEqualSigs(prgbofs, info); return true; } private bool GetStandardAndLiftedBinopSignatures(List<BinOpFullSig> rgbofs, BinOpArgInfo info) { int num = 0; for (int i = 0; i < s_binopSignatures.Length; i++) { BinOpSig binOpSig = s_binopSignatures[i]; if ((binOpSig.mask & info.mask) != 0) { CType cType = GetPredefindType(binOpSig.pt1); CType cType2 = GetPredefindType(binOpSig.pt2); if (cType != null && cType2 != null) { ConvKind convKind = GetConvKind(info.pt1, binOpSig.pt1); ConvKind convKind2 = GetConvKind(info.pt2, binOpSig.pt2); LiftFlags liftFlags = LiftFlags.None; switch (convKind) { case ConvKind.Explicit: { ExprConstant exprConstant = info.arg1 as ExprConstant; if (exprConstant == null) break; if (!canConvert(exprConstant, cType)) { if (i < num || !binOpSig.CanLift()) break; cType = TypeManager.GetNullable(cType); if (!canConvert(exprConstant, cType)) break; ConvKind convKind4 = GetConvKind(info.ptRaw1, binOpSig.pt1); liftFlags = (((uint)(convKind4 - 1) <= 1) ? (liftFlags | LiftFlags.Lift1) : (liftFlags | LiftFlags.Convert1)); } goto case ConvKind.Implicit; } case ConvKind.Unknown: if (!canConvert(info.arg1, cType)) { if (i < num || !binOpSig.CanLift()) break; cType = TypeManager.GetNullable(cType); if (!canConvert(info.arg1, cType)) break; ConvKind convKind3 = GetConvKind(info.ptRaw1, binOpSig.pt1); liftFlags = (((uint)(convKind3 - 1) <= 1) ? (liftFlags | LiftFlags.Lift1) : (liftFlags | LiftFlags.Convert1)); } goto case ConvKind.Implicit; case ConvKind.Identity: if (convKind2 == ConvKind.Identity) { BinOpFullSig binOpFullSig = new BinOpFullSig(this, binOpSig); if (binOpFullSig.Type1() != null && binOpFullSig.Type2() != null) { rgbofs.Add(binOpFullSig); return true; } } goto case ConvKind.Implicit; case ConvKind.Implicit: switch (convKind2) { case ConvKind.Explicit: { ExprConstant exprConstant2 = info.arg2 as ExprConstant; if (exprConstant2 == null) break; if (!canConvert(exprConstant2, cType2)) { if (i < num || !binOpSig.CanLift()) break; cType2 = TypeManager.GetNullable(cType2); if (!canConvert(exprConstant2, cType2)) break; ConvKind convKind6 = GetConvKind(info.ptRaw2, binOpSig.pt2); liftFlags = (((uint)(convKind6 - 1) <= 1) ? (liftFlags | LiftFlags.Lift2) : (liftFlags | LiftFlags.Convert2)); } goto case ConvKind.Identity; } case ConvKind.Unknown: if (!canConvert(info.arg2, cType2)) { if (i < num || !binOpSig.CanLift()) break; cType2 = TypeManager.GetNullable(cType2); if (!canConvert(info.arg2, cType2)) break; ConvKind convKind5 = GetConvKind(info.ptRaw2, binOpSig.pt2); liftFlags = (((uint)(convKind5 - 1) <= 1) ? (liftFlags | LiftFlags.Lift2) : (liftFlags | LiftFlags.Convert2)); } goto case ConvKind.Identity; case ConvKind.Identity: case ConvKind.Implicit: if (liftFlags != 0) { rgbofs.Add(new BinOpFullSig(cType, cType2, binOpSig.pfn, binOpSig.grfos, liftFlags, binOpSig.fnkind)); num = i + binOpSig.cbosSkip + 1; } else { rgbofs.Add(new BinOpFullSig(this, binOpSig)); i += binOpSig.cbosSkip; } break; } break; } } } } return false; } private int FindBestSignatureInList(List<BinOpFullSig> binopSignatures, BinOpArgInfo info) { if (binopSignatures.Count == 1) return 0; int num = 0; for (int i = 1; i < binopSignatures.Count; i++) { if (num < 0) num = i; else { int num2 = WhichBofsIsBetter(binopSignatures[num], binopSignatures[i], info.type1, info.type2); if (num2 == 0) num = -1; else if (num2 > 0) { num = i; } } } if (num == -1) return -1; for (int i = 0; i < binopSignatures.Count; i++) { if (i != num && WhichBofsIsBetter(binopSignatures[num], binopSignatures[i], info.type1, info.type2) >= 0) return -1; } return num; } private static ExprBinOp BindNullEqualityComparison(ExpressionKind ek, BinOpArgInfo info) { Expr arg = info.arg1; Expr right = info.arg2; if (info.binopKind == BinOpKind.Equal) { CType predefindType = GetPredefindType(PredefinedType.PT_BOOL); ExprBinOp exprBinOp = null; if (info.type1 is NullableType && info.type2 is NullType) { right = ExprFactory.CreateZeroInit(info.type1); exprBinOp = ExprFactory.CreateBinop(ek, predefindType, arg, right); } if (info.type1 is NullType && info.type2 is NullableType) { arg = ExprFactory.CreateZeroInit(info.type2); exprBinOp = ExprFactory.CreateBinop(ek, predefindType, arg, right); } if (exprBinOp != null) { exprBinOp.IsLifted = true; return exprBinOp; } } throw BadOperatorTypesError(info.arg1, info.arg2); } public Expr BindStandardBinop(ExpressionKind ek, Expr arg1, Expr arg2) { (BinOpKind, EXPRFLAG) binopKindAndFlags = GetBinopKindAndFlags(ek); BinOpKind item = binopKindAndFlags.Item1; EXPRFLAG item2 = binopKindAndFlags.Item2; BinOpArgInfo binOpArgInfo = new BinOpArgInfo(arg1, arg2) { binopKind = item }; binOpArgInfo.mask = (BinOpMask)(1 << (int)binOpArgInfo.binopKind); List<BinOpFullSig> list = new List<BinOpFullSig>(); ExprBinOp exprBinOp = BindUserDefinedBinOp(ek, binOpArgInfo); if (exprBinOp != null) return exprBinOp; bool flag = GetSpecialBinopSignatures(list, binOpArgInfo); if (!flag) flag = GetStandardAndLiftedBinopSignatures(list, binOpArgInfo); int num; if (flag) num = list.Count - 1; else { if (list.Count == 0) return BindNullEqualityComparison(ek, binOpArgInfo); num = FindBestSignatureInList(list, binOpArgInfo); if (num < 0) throw AmbiguousOperatorError(arg1, arg2); } return BindStandardBinopCore(binOpArgInfo, list[num], ek, item2); } private Expr BindStandardBinopCore(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags) { if (bofs.pfn == null) throw BadOperatorTypesError(info.arg1, info.arg2); if (!bofs.isLifted() || !bofs.AutoLift()) { Expr expr = info.arg1; Expr expr2 = info.arg2; if (bofs.ConvertOperandsBeforeBinding()) { expr = mustConvert(expr, bofs.Type1()); expr2 = mustConvert(expr2, bofs.Type2()); } if (bofs.fnkind == BinOpFuncKind.BoolBitwiseOp) return BindBoolBitwiseOp(ek, flags, expr, expr2); return bofs.pfn(this, ek, flags, expr, expr2); } if (IsEnumArithmeticBinOp(ek, info)) { Expr expr3 = info.arg1; Expr expr4 = info.arg2; if (bofs.ConvertOperandsBeforeBinding()) { expr3 = mustConvert(expr3, bofs.Type1()); expr4 = mustConvert(expr4, bofs.Type2()); } return BindLiftedEnumArithmeticBinOp(ek, flags, expr3, expr4); } return BindLiftedStandardBinOp(info, bofs, ek, flags); } private ExprBinOp BindLiftedStandardBinOp(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags) { Expr arg = info.arg1; Expr arg2 = info.arg2; Expr expr = null; LiftArgument(arg, bofs.Type1(), bofs.ConvertFirst(), out Expr ppLiftedArgument, out Expr ppNonLiftedArgument); LiftArgument(arg2, bofs.Type2(), bofs.ConvertSecond(), out Expr ppLiftedArgument2, out Expr ppNonLiftedArgument2); if (!ppNonLiftedArgument.isNull() && !ppNonLiftedArgument2.isNull()) expr = bofs.pfn(this, ek, flags, ppNonLiftedArgument, ppNonLiftedArgument2); CType cType; if (info.binopKind == BinOpKind.Compare || info.binopKind == BinOpKind.Equal) cType = GetPredefindType(PredefinedType.PT_BOOL); else { cType = ((bofs.fnkind == BinOpFuncKind.EnumBinOp) ? GetEnumBinOpType(ek, ppNonLiftedArgument.Type, ppNonLiftedArgument2.Type, out AggregateType _) : ppLiftedArgument.Type); if (!(cType is NullableType)) cType = TypeManager.GetNullable(cType); } ExprBinOp exprBinOp = ExprFactory.CreateBinop(ek, cType, ppLiftedArgument, ppLiftedArgument2); mustCast(expr, cType, (CONVERTTYPE)0); exprBinOp.IsLifted = true; exprBinOp.Flags |= flags; return exprBinOp; } private void LiftArgument(Expr pArgument, CType pParameterType, bool bConvertBeforeLift, out Expr ppLiftedArgument, out Expr ppNonLiftedArgument) { Expr expr = mustConvert(pArgument, pParameterType); if (expr != pArgument) MarkAsIntermediateConversion(expr); Expr expr2 = pArgument; NullableType nullableType = pParameterType as NullableType; if (nullableType != null) { if (expr2.isNull()) expr2 = mustCast(expr2, pParameterType); expr2 = mustCast(expr2, nullableType.UnderlyingType); if (bConvertBeforeLift) MarkAsIntermediateConversion(expr2); } else expr2 = expr; ppLiftedArgument = expr; ppNonLiftedArgument = expr2; } private bool GetDelBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info) { if (!info.ValidForDelegate() || (!info.type1.IsDelegateType && !info.type2.IsDelegateType)) return false; if (info.type1 == info.type2) { prgbofs.Add(new BinOpFullSig(info.type1, info.type2, BindDelBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.DelBinOp)); return true; } bool flag = info.type2.IsDelegateType && canConvert(info.arg1, info.type2); bool flag2 = info.type1.IsDelegateType && canConvert(info.arg2, info.type1); if (flag) prgbofs.Add(new BinOpFullSig(info.type2, info.type2, BindDelBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.DelBinOp)); if (flag2) prgbofs.Add(new BinOpFullSig(info.type1, info.type1, BindDelBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.DelBinOp)); return false; } private bool CanConvertArg1(BinOpArgInfo info, CType typeDst, out LiftFlags pgrflt, out CType ptypeSig1, out CType ptypeSig2) { ptypeSig1 = null; ptypeSig2 = null; if (canConvert(info.arg1, typeDst)) pgrflt = LiftFlags.None; else { pgrflt = LiftFlags.None; typeDst = TypeManager.GetNullable(typeDst); if (!canConvert(info.arg1, typeDst)) return false; pgrflt = LiftFlags.Convert1; } ptypeSig1 = typeDst; if (info.type2 is NullableType) { pgrflt |= LiftFlags.Lift2; ptypeSig2 = TypeManager.GetNullable(info.typeRaw2); } else ptypeSig2 = info.typeRaw2; return true; } private bool CanConvertArg2(BinOpArgInfo info, CType typeDst, out LiftFlags pgrflt, out CType ptypeSig1, out CType ptypeSig2) { ptypeSig1 = null; ptypeSig2 = null; if (canConvert(info.arg2, typeDst)) pgrflt = LiftFlags.None; else { pgrflt = LiftFlags.None; typeDst = TypeManager.GetNullable(typeDst); if (!canConvert(info.arg2, typeDst)) return false; pgrflt = LiftFlags.Convert2; } ptypeSig2 = typeDst; if (info.type1 is NullableType) { pgrflt |= LiftFlags.Lift1; ptypeSig1 = TypeManager.GetNullable(info.typeRaw1); } else ptypeSig1 = info.typeRaw1; return true; } private static void RecordBinOpSigFromArgs(List<BinOpFullSig> prgbofs, BinOpArgInfo info) { LiftFlags liftFlags = LiftFlags.None; CType type; if (info.type1 != info.typeRaw1) { liftFlags |= LiftFlags.Lift1; type = TypeManager.GetNullable(info.typeRaw1); } else type = info.typeRaw1; CType type2; if (info.type2 != info.typeRaw2) { liftFlags |= LiftFlags.Lift2; type2 = TypeManager.GetNullable(info.typeRaw2); } else type2 = info.typeRaw2; prgbofs.Add(new BinOpFullSig(type, type2, BindEnumBinOp, OpSigFlags.Value, liftFlags, BinOpFuncKind.EnumBinOp)); } private bool GetEnumBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info) { if (!info.typeRaw1.IsEnumType && !info.typeRaw2.IsEnumType) return false; CType ptypeSig = null; CType ptypeSig2 = null; LiftFlags pgrflt = LiftFlags.None; if (info.typeRaw1 == info.typeRaw2) { if (!info.ValidForEnum()) return false; RecordBinOpSigFromArgs(prgbofs, info); return true; } if ((!info.typeRaw1.IsEnumType) ? (info.typeRaw1 == info.typeRaw2.UnderlyingEnumType && info.ValidForUnderlyingTypeAndEnum()) : (info.typeRaw2 == info.typeRaw1.UnderlyingEnumType && info.ValidForEnumAndUnderlyingType())) { RecordBinOpSigFromArgs(prgbofs, info); return true; } if ((!info.typeRaw1.IsEnumType) ? ((info.ValidForEnum() && CanConvertArg1(info, info.typeRaw2, out pgrflt, out ptypeSig, out ptypeSig2)) || (info.ValidForEnumAndUnderlyingType() && CanConvertArg1(info, info.typeRaw2.UnderlyingEnumType, out pgrflt, out ptypeSig, out ptypeSig2))) : ((info.ValidForEnum() && CanConvertArg2(info, info.typeRaw1, out pgrflt, out ptypeSig, out ptypeSig2)) || (info.ValidForEnumAndUnderlyingType() && CanConvertArg2(info, info.typeRaw1.UnderlyingEnumType, out pgrflt, out ptypeSig, out ptypeSig2)))) prgbofs.Add(new BinOpFullSig(ptypeSig, ptypeSig2, BindEnumBinOp, OpSigFlags.Value, pgrflt, BinOpFuncKind.EnumBinOp)); return false; } private static bool IsEnumArithmeticBinOp(ExpressionKind ek, BinOpArgInfo info) { switch (ek) { case ExpressionKind.Add: return info.typeRaw1.IsEnumType ^ info.typeRaw2.IsEnumType; case ExpressionKind.Subtract: return info.typeRaw1.IsEnumType | info.typeRaw2.IsEnumType; default: return false; } } private bool GetRefEqualSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info) { if (info.mask != BinOpMask.Equal) return false; if (info.type1 != info.typeRaw1 || info.type2 != info.typeRaw2) return false; bool result = false; CType cType = info.type1; CType cType2 = info.type2; CType predefindType = GetPredefindType(PredefinedType.PT_OBJECT); CType cType3 = null; if (cType is NullType && cType2 is NullType) { cType3 = predefindType; result = true; } else { CType predefindType2 = GetPredefindType(PredefinedType.PT_DELEGATE); if (canConvert(info.arg1, predefindType2) && canConvert(info.arg2, predefindType2) && !cType.IsDelegateType && !cType2.IsDelegateType) prgbofs.Add(new BinOpFullSig(predefindType2, predefindType2, BindDelBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.DelBinOp)); if (cType.FundamentalType != FUNDTYPE.FT_REF) return false; if (cType2 is NullType) { result = true; cType3 = predefindType; } else { if (cType2.FundamentalType != FUNDTYPE.FT_REF) return false; if (cType is NullType) { result = true; cType3 = predefindType; } else { if (!canCast(cType, cType2, CONVERTTYPE.NOUDC) && !canCast(cType2, cType, CONVERTTYPE.NOUDC)) return false; if (cType.IsInterfaceType || cType.IsPredefType(PredefinedType.PT_STRING) || SymbolLoader.HasBaseConversion(cType, predefindType2)) cType = predefindType; else if (cType is ArrayType) { cType = GetPredefindType(PredefinedType.PT_ARRAY); } else if (!cType.IsClassType) { return false; } if (cType2.IsInterfaceType || cType2.IsPredefType(PredefinedType.PT_STRING) || SymbolLoader.HasBaseConversion(cType2, predefindType2)) cType2 = predefindType; else if (cType2 is ArrayType) { cType2 = GetPredefindType(PredefinedType.PT_ARRAY); } else if (!cType2.IsClassType) { return false; } if (SymbolLoader.HasBaseConversion(cType2, cType)) cType3 = cType; else if (SymbolLoader.HasBaseConversion(cType, cType2)) { cType3 = cType2; } } } } prgbofs.Add(new BinOpFullSig(cType3, cType3, BindRefCmpOp, OpSigFlags.None, LiftFlags.None, BinOpFuncKind.RefCmpOp)); return result; } private int WhichBofsIsBetter(BinOpFullSig bofs1, BinOpFullSig bofs2, CType type1, CType type2) { BetterType betterType; BetterType betterType2; if (bofs1.FPreDef() && bofs2.FPreDef()) { betterType = WhichTypeIsBetter(bofs1.pt1, bofs2.pt1, type1); betterType2 = WhichTypeIsBetter(bofs1.pt2, bofs2.pt2, type2); } else { betterType = WhichTypeIsBetter(bofs1.Type1(), bofs2.Type1(), type1); betterType2 = WhichTypeIsBetter(bofs1.Type2(), bofs2.Type2(), type2); } int num; switch (betterType) { case BetterType.Left: num = -1; break; case BetterType.Right: num = 1; break; default: num = 0; break; } switch (betterType2) { case BetterType.Left: num--; break; case BetterType.Right: num++; break; } return num; } private static (ExpressionKind, UnaOpKind, EXPRFLAG) CalculateExprAndUnaryOpKinds(OperatorKind op, bool bChecked) { EXPRFLAG eXPRFLAG = (EXPRFLAG)0; UnaOpKind item; ExpressionKind item2; switch (op) { case OperatorKind.OP_UPLUS: item = UnaOpKind.Plus; item2 = ExpressionKind.UnaryPlus; break; case OperatorKind.OP_NEG: if (bChecked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = UnaOpKind.Minus; item2 = ExpressionKind.Negate; break; case OperatorKind.OP_BITNOT: item = UnaOpKind.Tilde; item2 = ExpressionKind.BitwiseNot; break; case OperatorKind.OP_LOGNOT: item = UnaOpKind.Bang; item2 = ExpressionKind.LogicalNot; break; case OperatorKind.OP_POSTINC: eXPRFLAG = EXPRFLAG.EXF_OPERATOR; if (bChecked) eXPRFLAG |= EXPRFLAG.EXF_CHECKOVERFLOW; item = UnaOpKind.IncDec; item2 = ExpressionKind.Add; break; case OperatorKind.OP_PREINC: if (bChecked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = UnaOpKind.IncDec; item2 = ExpressionKind.Add; break; case OperatorKind.OP_POSTDEC: eXPRFLAG = EXPRFLAG.EXF_OPERATOR; if (bChecked) eXPRFLAG |= EXPRFLAG.EXF_CHECKOVERFLOW; item = UnaOpKind.IncDec; item2 = ExpressionKind.Subtract; break; case OperatorKind.OP_PREDEC: if (bChecked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = UnaOpKind.IncDec; item2 = ExpressionKind.Subtract; break; default: throw Error.InternalCompilerError(); } return (item2, item, eXPRFLAG); } public Expr BindStandardUnaryOperator(OperatorKind op, Expr pArgument) { CType type = pArgument.Type; NullableType nullableType = type as NullableType; if (nullableType != null) { CType underlyingType = nullableType.UnderlyingType; if (underlyingType.IsEnumType) { PredefinedType pt; switch (underlyingType.FundamentalType) { case FUNDTYPE.FT_U4: pt = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: pt = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: pt = PredefinedType.PT_ULONG; break; default: pt = PredefinedType.PT_INT; break; } return mustCast(BindStandardUnaryOperator(op, mustCast(pArgument, TypeManager.GetNullable(GetPredefindType(pt)))), nullableType); } } (ExpressionKind, UnaOpKind, EXPRFLAG) valueTuple = CalculateExprAndUnaryOpKinds(op, Context.Checked); ExpressionKind item = valueTuple.Item1; UnaOpKind item2 = valueTuple.Item2; EXPRFLAG item3 = valueTuple.Item3; UnaOpMask unaryOpMask = (UnaOpMask)(1 << (int)item2); List<UnaOpFullSig> list = new List<UnaOpFullSig>(); Expr ppResult; UnaryOperatorSignatureFindResult unaryOperatorSignatureFindResult = PopulateSignatureList(pArgument, item2, unaryOpMask, item, item3, list, out ppResult); int num = list.Count - 1; switch (unaryOperatorSignatureFindResult) { case UnaryOperatorSignatureFindResult.Return: return ppResult; default: if (!FindApplicableSignatures(pArgument, unaryOpMask, list)) { if (list.Count == 0) throw BadOperatorTypesError(pArgument, null); num = 0; if (list.Count != 1) { for (int i = 1; i < list.Count; i++) { if (num < 0) num = i; else { int num2 = WhichUofsIsBetter(list[num], list[i], type); if (num2 == 0) num = -1; else if (num2 > 0) { num = i; } } } if (num < 0) throw AmbiguousOperatorError(pArgument, null); for (int j = 0; j < list.Count; j++) { if (j != num && WhichUofsIsBetter(list[num], list[j], type) >= 0) throw AmbiguousOperatorError(pArgument, null); } } } else num = list.Count - 1; break; case UnaryOperatorSignatureFindResult.Match: break; } UnaOpFullSig unaOpFullSig = list[num]; if (unaOpFullSig.pfn == null) { if (item2 == UnaOpKind.IncDec) return BindIncOp(item, item3, pArgument, unaOpFullSig); throw BadOperatorTypesError(pArgument, null); } if (unaOpFullSig.isLifted()) return BindLiftedStandardUnop(item, item3, pArgument, unaOpFullSig); if (pArgument is ExprConstant) pArgument = ExprFactory.CreateCast(pArgument.Type, pArgument); Expr expr = tryConvert(pArgument, unaOpFullSig.GetType()); if (expr == null) expr = mustCast(pArgument, unaOpFullSig.GetType(), CONVERTTYPE.NOUDC); return unaOpFullSig.pfn(this, item, item3, expr); } private UnaryOperatorSignatureFindResult PopulateSignatureList(Expr pArgument, UnaOpKind unaryOpKind, UnaOpMask unaryOpMask, ExpressionKind exprKind, EXPRFLAG flags, List<UnaOpFullSig> pSignatures, out Expr ppResult) { ppResult = null; CType type = pArgument.Type; CType cType = type.StripNubs(); PredefinedType predefinedType = cType.IsPredefined ? cType.PredefinedType : PredefinedType.PT_COUNT; if (predefinedType > PredefinedType.PT_ULONG) { if (cType.IsEnumType) { if ((unaryOpMask & (UnaOpMask.Tilde | UnaOpMask.IncDec)) != 0) { if (unaryOpKind == UnaOpKind.Tilde) pSignatures.Add(new UnaOpFullSig(((AggregateType)type).OwningAggregate.GetUnderlyingType(), BindEnumUnaOp, LiftFlags.None, UnaOpFuncKind.EnumUnaOp)); else pSignatures.Add(new UnaOpFullSig(((AggregateType)type).OwningAggregate.GetUnderlyingType(), null, LiftFlags.None, UnaOpFuncKind.None)); return UnaryOperatorSignatureFindResult.Match; } } else if (unaryOpKind == UnaOpKind.IncDec) { ExprMultiGet exprMultiGet = ExprFactory.CreateMultiGet((EXPRFLAG)0, type, null); Expr expr = bindUDUnop(exprKind - 42 + 33, exprMultiGet); if (expr != null) { if (expr.Type != null && expr.Type != type) expr = mustConvert(expr, type); ExprMulti exprMulti2 = exprMultiGet.OptionalMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, type, pArgument, expr); CheckLvalue(pArgument, CheckLvalueKind.Increment); ppResult = exprMulti2; return UnaryOperatorSignatureFindResult.Return; } } else { Expr expr2 = bindUDUnop(exprKind, pArgument); if (expr2 != null) { ppResult = expr2; return UnaryOperatorSignatureFindResult.Return; } } } return UnaryOperatorSignatureFindResult.Continue; } private bool FindApplicableSignatures(Expr pArgument, UnaOpMask unaryOpMask, List<UnaOpFullSig> pSignatures) { long num = 0; CType type = pArgument.Type; CType cType = type.StripNubs(); PredefinedType ptSrc = type.IsPredefined ? type.PredefinedType : PredefinedType.PT_COUNT; PredefinedType ptSrc2 = cType.IsPredefined ? cType.PredefinedType : PredefinedType.PT_COUNT; for (int i = 0; i < s_rguos.Length; i++) { UnaOpSig unaOpSig = s_rguos[i]; if ((unaOpSig.grfuom & unaryOpMask) != 0) { ConvKind convKind = GetConvKind(ptSrc, s_rguos[i].pt); CType cType2 = null; switch (convKind) { case ConvKind.Explicit: if (!(pArgument is ExprConstant)) break; if (!canConvert(pArgument, cType2 = GetPredefindType(unaOpSig.pt))) { if (i < num) break; cType2 = TypeManager.GetNullable(cType2); if (!canConvert(pArgument, cType2)) break; } goto case ConvKind.Implicit; case ConvKind.Unknown: if (!canConvert(pArgument, cType2 = GetPredefindType(unaOpSig.pt))) { if (i < num) break; cType2 = TypeManager.GetNullable(cType2); if (!canConvert(pArgument, cType2)) break; } goto case ConvKind.Implicit; case ConvKind.Identity: { UnaOpFullSig unaOpFullSig = new UnaOpFullSig(this, unaOpSig); if (unaOpFullSig.GetType() != null) { pSignatures.Add(unaOpFullSig); return true; } goto case ConvKind.Implicit; } case ConvKind.Implicit: if (cType2 is NullableType) { LiftFlags liftFlags = LiftFlags.None; ConvKind convKind2 = GetConvKind(ptSrc2, unaOpSig.pt); liftFlags = (((uint)(convKind2 - 1) <= 1) ? (liftFlags | LiftFlags.Lift1) : (liftFlags | LiftFlags.Convert1)); pSignatures.Add(new UnaOpFullSig(cType2, unaOpSig.pfn, liftFlags, unaOpSig.fnkind)); num = i + unaOpSig.cuosSkip + 1; } else { UnaOpFullSig unaOpFullSig2 = new UnaOpFullSig(this, unaOpSig); if (unaOpFullSig2.GetType() != null) pSignatures.Add(unaOpFullSig2); i += unaOpSig.cuosSkip; } break; } } } return false; } private ExprOperator BindLiftedStandardUnop(ExpressionKind ek, EXPRFLAG flags, Expr arg, UnaOpFullSig uofs) { NullableType nullableType = uofs.GetType() as NullableType; if (arg.Type is NullType) throw BadOperatorTypesError(arg, null); LiftArgument(arg, uofs.GetType(), uofs.Convert(), out Expr ppLiftedArgument, out Expr ppNonLiftedArgument); Expr expr = uofs.pfn(this, ek, flags, ppNonLiftedArgument); ExprUnaryOp exprUnaryOp = ExprFactory.CreateUnaryOp(ek, nullableType, ppLiftedArgument); mustCast(expr, nullableType, (CONVERTTYPE)0); exprUnaryOp.Flags |= flags; return exprUnaryOp; } private int WhichUofsIsBetter(UnaOpFullSig uofs1, UnaOpFullSig uofs2, CType typeArg) { switch ((!uofs1.FPreDef() || !uofs2.FPreDef()) ? WhichTypeIsBetter(uofs1.GetType(), uofs2.GetType(), typeArg) : WhichTypeIsBetter(uofs1.pt, uofs2.pt, typeArg)) { case BetterType.Left: return -1; case BetterType.Right: return 1; default: return 0; } } private static ExprOperator BindIntBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { return binder.BindIntOp(ek, flags, arg1, arg2, arg1.Type.PredefinedType); } private static ExprOperator BindIntUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg) { return binder.BindIntOp(ek, flags, arg, null, arg.Type.PredefinedType); } private static ExprOperator BindRealBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG _, Expr arg1, Expr arg2) { return BindFloatOp(ek, arg1, arg2); } private static ExprOperator BindRealUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG _, Expr arg) { return BindFloatOp(ek, arg, null); } private Expr BindIncOp(ExpressionKind ek, EXPRFLAG flags, Expr arg, UnaOpFullSig uofs) { CheckLvalue(arg, CheckLvalueKind.Increment); CType cType = uofs.GetType().StripNubs(); FUNDTYPE fundamentalType = cType.FundamentalType; if (fundamentalType == FUNDTYPE.FT_R8 || fundamentalType == FUNDTYPE.FT_R4) flags &= ~EXPRFLAG.EXF_CHECKOVERFLOW; if (uofs.isLifted()) return BindLiftedIncOp(ek, flags, arg, uofs); return BindNonliftedIncOp(ek, flags, arg, uofs); } private Expr BindIncOpCore(ExpressionKind ek, EXPRFLAG flags, Expr exprVal, CType type) { if (type.IsEnumType && type.FundamentalType > FUNDTYPE.FT_U8) type = GetPredefindType(PredefinedType.PT_INT); ConstVal cv; switch (type.FundamentalType) { default: { PREDEFMETH predefMeth; if (ek == ExpressionKind.Add) { ek = ExpressionKind.DecimalInc; predefMeth = PREDEFMETH.PM_DECIMAL_OPINCREMENT; } else { ek = ExpressionKind.DecimalDec; predefMeth = PREDEFMETH.PM_DECIMAL_OPDECREMENT; } return CreateUnaryOpForPredefMethodCall(ek, predefMeth, type, exprVal); } case FUNDTYPE.FT_I1: case FUNDTYPE.FT_I2: case FUNDTYPE.FT_U1: case FUNDTYPE.FT_U2: type = GetPredefindType(PredefinedType.PT_INT); cv = ConstVal.Get(1); break; case FUNDTYPE.FT_I4: case FUNDTYPE.FT_U4: cv = ConstVal.Get(1); break; case FUNDTYPE.FT_I8: case FUNDTYPE.FT_U8: cv = ConstVal.Get(1); break; case FUNDTYPE.FT_R4: case FUNDTYPE.FT_R8: cv = ConstVal.Get(1); break; } return LScalar(ek, flags, exprVal, type, cv, type); } private Expr LScalar(ExpressionKind ek, EXPRFLAG flags, Expr exprVal, CType type, ConstVal cv, CType typeTmp) { CType cType = type; if (cType.IsEnumType) cType = cType.UnderlyingEnumType; ExprBinOp exprBinOp = ExprFactory.CreateBinop(ek, typeTmp, exprVal, ExprFactory.CreateConstant(cType, cv)); exprBinOp.Flags |= flags; if (typeTmp == type) return exprBinOp; return mustCast(exprBinOp, type, CONVERTTYPE.NOUDC); } private ExprMulti BindNonliftedIncOp(ExpressionKind ek, EXPRFLAG flags, Expr arg, UnaOpFullSig uofs) { ExprMultiGet exprMultiGet = ExprFactory.CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null); Expr expr = exprMultiGet; CType type = uofs.GetType(); expr = mustCast(expr, type); expr = BindIncOpCore(ek, flags, expr, type); Expr op = mustCast(expr, arg.Type, CONVERTTYPE.NOUDC); return exprMultiGet.OptionalMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, op); } private ExprMulti BindLiftedIncOp(ExpressionKind ek, EXPRFLAG flags, Expr arg, UnaOpFullSig uofs) { NullableType nullableType = uofs.GetType() as NullableType; ExprMultiGet exprMultiGet = ExprFactory.CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null); Expr expr = exprMultiGet; Expr expr2 = expr; expr2 = mustCast(expr2, nullableType.UnderlyingType); Expr expr3 = BindIncOpCore(ek, flags, expr2, nullableType.UnderlyingType); expr = mustCast(expr, nullableType); ExprUnaryOp exprUnaryOp = ExprFactory.CreateUnaryOp((ek == ExpressionKind.Add) ? ExpressionKind.Inc : ExpressionKind.Dec, arg.Type, expr); mustCast(mustCast(expr3, nullableType), arg.Type); exprUnaryOp.Flags |= flags; return exprMultiGet.OptionalMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, exprUnaryOp); } private static ExprBinOp BindDecBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { CType predefindType = GetPredefindType(PredefinedType.PT_DECIMAL); CType type = ((uint)(ek - 36) <= 5) ? GetPredefindType(PredefinedType.PT_BOOL) : (((uint)(ek - 42) <= 4) ? predefindType : null); return ExprFactory.CreateBinop(ek, type, arg1, arg2); } private static ExprUnaryOp BindDecUnaOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg) { CType predefindType = GetPredefindType(PredefinedType.PT_DECIMAL); if (ek == ExpressionKind.Negate) { PREDEFMETH predefMeth = PREDEFMETH.PM_DECIMAL_OPUNARYMINUS; return CreateUnaryOpForPredefMethodCall(ExpressionKind.DecimalNegate, predefMeth, predefindType, arg); } return ExprFactory.CreateUnaryOp(ExpressionKind.UnaryPlus, predefindType, arg); } private static Expr BindStrBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { return BindStringConcat(arg1, arg2); } private static ExprBinOp BindShiftOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { PredefinedType predefinedType = arg1.Type.PredefinedType; return ExprFactory.CreateBinop(ek, arg1.Type, arg1, arg2); } private static ExprBinOp BindBoolBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { return ExprFactory.CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2); } private ExprOperator BindBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2) { if (expr1.Type is NullableType || expr2.Type is NullableType) { CType predefindType = GetPredefindType(PredefinedType.PT_BOOL); CType nullable = TypeManager.GetNullable(predefindType); Expr expr3 = StripNullableConstructor(expr1); Expr expr4 = StripNullableConstructor(expr2); Expr expr5 = null; if (!(expr3.Type is NullableType) && !(expr4.Type is NullableType)) expr5 = BindBoolBinOp(this, ek, flags, expr3, expr4); ExprBinOp exprBinOp = ExprFactory.CreateBinop(ek, nullable, expr1, expr2); if (expr5 != null) mustCast(expr5, nullable, (CONVERTTYPE)0); exprBinOp.IsLifted = true; exprBinOp.Flags |= flags; return exprBinOp; } return BindBoolBinOp(this, ek, flags, expr1, expr2); } private static Expr BindLiftedBoolBitwiseOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2) { return null; } private static Expr BindBoolUnaOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg) { CType predefindType = GetPredefindType(PredefinedType.PT_BOOL); Expr const = arg.GetConst(); if (const == null) return ExprFactory.CreateUnaryOp(ExpressionKind.LogicalNot, predefindType, arg); return ExprFactory.CreateConstant(predefindType, ConstVal.Get(((ExprConstant)const).Val.Int32Val == 0)); } private static ExprBinOp BindStrCmpOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { PREDEFMETH predefMeth = (ek == ExpressionKind.Eq) ? PREDEFMETH.PM_STRING_OPEQUALITY : PREDEFMETH.PM_STRING_OPINEQUALITY; ek = ((ek == ExpressionKind.Eq) ? ExpressionKind.StringEq : ExpressionKind.StringNotEq); return CreateBinopForPredefMethodCall(ek, predefMeth, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2); } private static ExprBinOp BindRefCmpOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { arg1 = binder.mustConvert(arg1, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC); arg2 = binder.mustConvert(arg2, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC); return ExprFactory.CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2); } private static Expr BindDelBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { PREDEFMETH predefMeth = PREDEFMETH.PM_DECIMAL_OPDECREMENT; CType retType = null; switch (ek) { case ExpressionKind.Add: predefMeth = PREDEFMETH.PM_DELEGATE_COMBINE; retType = arg1.Type; ek = ExpressionKind.DelegateAdd; break; case ExpressionKind.Subtract: predefMeth = PREDEFMETH.PM_DELEGATE_REMOVE; retType = arg1.Type; ek = ExpressionKind.DelegateSubtract; break; case ExpressionKind.Eq: predefMeth = PREDEFMETH.PM_DELEGATE_OPEQUALITY; retType = GetPredefindType(PredefinedType.PT_BOOL); ek = ExpressionKind.DelegateEq; break; case ExpressionKind.NotEq: predefMeth = PREDEFMETH.PM_DELEGATE_OPINEQUALITY; retType = GetPredefindType(PredefinedType.PT_BOOL); ek = ExpressionKind.DelegateNotEq; break; } return CreateBinopForPredefMethodCall(ek, predefMeth, retType, arg1, arg2); } private static Expr BindEnumBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { AggregateType ppEnumType; AggregateType enumBinOpType = GetEnumBinOpType(ek, arg1.Type, arg2.Type, out ppEnumType); PredefinedType predefinedType; switch (ppEnumType.FundamentalType) { default: predefinedType = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: predefinedType = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: predefinedType = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: predefinedType = PredefinedType.PT_ULONG; break; } CType predefindType = GetPredefindType(predefinedType); arg1 = binder.mustCast(arg1, predefindType, CONVERTTYPE.NOUDC); arg2 = binder.mustCast(arg2, predefindType, CONVERTTYPE.NOUDC); Expr expr = binder.BindIntOp(ek, flags, arg1, arg2, predefinedType); if (expr.Type != enumBinOpType) expr = binder.mustCast(expr, enumBinOpType, CONVERTTYPE.NOUDC); return expr; } private Expr BindLiftedEnumArithmeticBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2) { NullableType nullableType = arg1.Type as NullableType; CType cType = (nullableType != null) ? nullableType.UnderlyingType : arg1.Type; NullableType nullableType2 = arg2.Type as NullableType; CType cType2 = (nullableType2 != null) ? nullableType2.UnderlyingType : arg2.Type; if (cType is NullType) cType = cType2.UnderlyingEnumType; else if (cType2 is NullType) { cType2 = cType.UnderlyingEnumType; } AggregateType ppEnumType; NullableType nullable = TypeManager.GetNullable(GetEnumBinOpType(ek, cType, cType2, out ppEnumType)); PredefinedType pt; switch (ppEnumType.FundamentalType) { default: pt = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: pt = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: pt = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: pt = PredefinedType.PT_ULONG; break; } NullableType nullable2 = TypeManager.GetNullable(GetPredefindType(pt)); arg1 = mustCast(arg1, nullable2, CONVERTTYPE.NOUDC); arg2 = mustCast(arg2, nullable2, CONVERTTYPE.NOUDC); ExprBinOp exprBinOp = ExprFactory.CreateBinop(ek, nullable2, arg1, arg2); exprBinOp.IsLifted = true; exprBinOp.Flags |= flags; if (exprBinOp.Type != nullable) return mustCast(exprBinOp, nullable, CONVERTTYPE.NOUDC); return exprBinOp; } private static Expr BindEnumUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg) { CType type = ((ExprCast)arg).Argument.Type; PredefinedType predefinedType; switch (type.FundamentalType) { default: predefinedType = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: predefinedType = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: predefinedType = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: predefinedType = PredefinedType.PT_ULONG; break; } CType predefindType = GetPredefindType(predefinedType); arg = binder.mustCast(arg, predefindType, CONVERTTYPE.NOUDC); Expr expr = binder.BindIntOp(ek, flags, arg, null, predefinedType); return binder.MustCastInUncheckedContext(expr, type, CONVERTTYPE.NOUDC); } private (BinOpKind, EXPRFLAG) GetBinopKindAndFlags(ExpressionKind ek) { EXPRFLAG eXPRFLAG = (EXPRFLAG)0; BindingContext context; BinOpKind item; switch (ek) { case ExpressionKind.Add: context = Context; if (context.Checked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = BinOpKind.Add; break; case ExpressionKind.Subtract: context = Context; if (context.Checked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = BinOpKind.Sub; break; case ExpressionKind.Divide: case ExpressionKind.Modulo: eXPRFLAG = EXPRFLAG.EXF_ASSGOP; context = Context; if (context.Checked) eXPRFLAG |= EXPRFLAG.EXF_CHECKOVERFLOW; item = BinOpKind.Mul; break; case ExpressionKind.Multiply: context = Context; if (context.Checked) eXPRFLAG = EXPRFLAG.EXF_CHECKOVERFLOW; item = BinOpKind.Mul; break; case ExpressionKind.BitwiseAnd: case ExpressionKind.BitwiseOr: item = BinOpKind.Bitwise; break; case ExpressionKind.BitwiseExclusiveOr: item = BinOpKind.BitXor; break; case ExpressionKind.LeftShirt: case ExpressionKind.RightShift: item = BinOpKind.Shift; break; case ExpressionKind.LogicalAnd: case ExpressionKind.LogicalOr: item = BinOpKind.Logical; break; case ExpressionKind.LessThan: case ExpressionKind.LessThanOrEqual: case ExpressionKind.GreaterThan: case ExpressionKind.GreaterThanOrEqual: item = BinOpKind.Compare; break; case ExpressionKind.Eq: case ExpressionKind.NotEq: item = BinOpKind.Equal; break; default: throw Error.InternalCompilerError(); } return (item, eXPRFLAG); } private ExprOperator BindIntOp(ExpressionKind kind, EXPRFLAG flags, Expr op1, Expr op2, PredefinedType ptOp) { CType predefindType = GetPredefindType(ptOp); if (kind == ExpressionKind.Negate) return BindIntegerNeg(flags, op1, ptOp); CType type = kind.IsRelational() ? GetPredefindType(PredefinedType.PT_BOOL) : predefindType; ExprOperator exprOperator = ExprFactory.CreateOperator(kind, type, op1, op2); exprOperator.Flags |= flags; return exprOperator; } private ExprOperator BindIntegerNeg(EXPRFLAG flags, Expr op, PredefinedType ptOp) { CType predefindType = GetPredefindType(ptOp); switch (ptOp) { case PredefinedType.PT_ULONG: throw BadOperatorTypesError(op, null); case PredefinedType.PT_UINT: if (op.Type.FundamentalType == FUNDTYPE.FT_U4) op = mustConvertCore(op, GetPredefindType(PredefinedType.PT_LONG), CONVERTTYPE.NOUDC); break; } return ExprFactory.CreateNeg(flags, op); } private static ExprOperator BindFloatOp(ExpressionKind kind, Expr op1, Expr op2) { CType type = kind.IsRelational() ? GetPredefindType(PredefinedType.PT_BOOL) : op1.Type; ExprOperator exprOperator = ExprFactory.CreateOperator(kind, type, op1, op2); exprOperator.Flags &= ~EXPRFLAG.EXF_CHECKOVERFLOW; return exprOperator; } private static ExprConcat BindStringConcat(Expr op1, Expr op2) { return ExprFactory.CreateConcat(op1, op2); } private static RuntimeBinderException AmbiguousOperatorError(Expr op1, Expr op2) { string errorString = op1.ErrorString; if (op2 == null) return ErrorHandling.Error(ErrorCode.ERR_AmbigUnaryOp, errorString, op1.Type); return ErrorHandling.Error(ErrorCode.ERR_AmbigBinaryOps, errorString, op1.Type, op2.Type); } private Expr BindUserBoolOp(ExpressionKind kind, ExprCall pCall) { CType type = pCall.Type; if (!TypeManager.SubstEqualTypes(type, pCall.MethWithInst.Meth().Params[0], type) || !TypeManager.SubstEqualTypes(type, pCall.MethWithInst.Meth().Params[1], type)) throw ErrorHandling.Error(ErrorCode.ERR_BadBoolOp, pCall.MethWithInst); ExprList exprList = (ExprList)pCall.OptionalArguments; Expr optionalElement = exprList.OptionalElement; ExprWrap exprWrap = (ExprWrap)(exprList.OptionalElement = WrapShortLivedExpression(optionalElement)); SymbolTable.PopulateSymbolTableWithName("op_True", null, exprWrap.Type.AssociatedSystemType); SymbolTable.PopulateSymbolTableWithName("op_False", null, exprWrap.Type.AssociatedSystemType); Expr expr2 = bindUDUnop(ExpressionKind.True, exprWrap); Expr expr3 = bindUDUnop(ExpressionKind.False, exprWrap); if (expr2 == null || expr3 == null) throw ErrorHandling.Error(ErrorCode.ERR_MustHaveOpTF, type); expr2 = mustConvert(expr2, GetPredefindType(PredefinedType.PT_BOOL)); expr3 = mustConvert(expr3, GetPredefindType(PredefinedType.PT_BOOL)); return ExprFactory.CreateUserLogOp(type, (kind == ExpressionKind.LogicalAnd) ? expr3 : expr2, pCall); } private static AggregateType GetUserDefinedBinopArgumentType(CType type) { NullableType nullableType = type as NullableType; if (nullableType != null) type = nullableType.UnderlyingType; AggregateType aggregateType = type as AggregateType; if (aggregateType != null && (aggregateType.IsClassType || aggregateType.IsStructType) && !aggregateType.OwningAggregate.IsSkipUDOps()) return aggregateType; return null; } private static int GetUserDefinedBinopArgumentTypes(CType type1, CType type2, AggregateType[] rgats) { int num = 0; rgats[0] = GetUserDefinedBinopArgumentType(type1); if (rgats[0] != null) num++; rgats[num] = GetUserDefinedBinopArgumentType(type2); if (rgats[num] != null) num++; if (num == 2 && rgats[0] == rgats[1]) num = 1; return num; } private static bool UserDefinedBinaryOperatorCanBeLifted(ExpressionKind ek, MethodSymbol method, AggregateType ats, TypeArray Params) { if (!Params[0].IsNonNullableValueType || !Params[1].IsNonNullableValueType) return false; CType cType = TypeManager.SubstType(method.RetType, ats); if (!cType.IsNonNullableValueType) return false; if ((uint)(ek - 36) <= 1) { if (!cType.IsPredefType(PredefinedType.PT_BOOL)) return false; if (Params[0] != Params[1]) return false; return true; } if ((uint)(ek - 38) <= 3) { if (!cType.IsPredefType(PredefinedType.PT_BOOL)) return false; return true; } return true; } private bool UserDefinedBinaryOperatorIsApplicable(List<CandidateFunctionMember> candidateList, ExpressionKind ek, MethodSymbol method, AggregateType ats, Expr arg1, Expr arg2, bool fDontLift) { if (!method.isOperator || method.Params.Count != 2) return false; TypeArray typeArray = TypeManager.SubstTypeArray(method.Params, ats); if (canConvert(arg1, typeArray[0]) && canConvert(arg2, typeArray[1])) { candidateList.Add(new CandidateFunctionMember(new MethPropWithInst(method, ats, TypeArray.Empty), typeArray, 0, false)); return true; } if (fDontLift || !UserDefinedBinaryOperatorCanBeLifted(ek, method, ats, typeArray)) return false; CType[] array = new CType[2] { TypeManager.GetNullable(typeArray[0]), TypeManager.GetNullable(typeArray[1]) }; if (!canConvert(arg1, array[0]) || !canConvert(arg2, array[1])) return false; candidateList.Add(new CandidateFunctionMember(new MethPropWithInst(method, ats, TypeArray.Empty), TypeArray.Allocate(array), 2, false)); return true; } private bool GetApplicableUserDefinedBinaryOperatorCandidates(List<CandidateFunctionMember> candidateList, ExpressionKind ek, AggregateType type, Expr arg1, Expr arg2, bool fDontLift) { Name name = ExpressionKindName(ek); bool result = false; for (MethodSymbol methodSymbol = SymbolLoader.LookupAggMember(name, type.OwningAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol; methodSymbol != null; methodSymbol = (methodSymbol.LookupNext(symbmask_t.MASK_MethodSymbol) as MethodSymbol)) { if (UserDefinedBinaryOperatorIsApplicable(candidateList, ek, methodSymbol, type, arg1, arg2, fDontLift)) result = true; } return result; } private AggregateType GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(List<CandidateFunctionMember> candidateList, ExpressionKind ek, AggregateType type, Expr arg1, Expr arg2, bool fDontLift, AggregateType atsStop) { AggregateType aggregateType = type; while (aggregateType != null && aggregateType != atsStop) { if (GetApplicableUserDefinedBinaryOperatorCandidates(candidateList, ek, aggregateType, arg1, arg2, fDontLift)) return aggregateType; aggregateType = aggregateType.BaseClass; } return null; } private ExprCall BindUDBinop(ExpressionKind ek, Expr arg1, Expr arg2, bool fDontLift, out MethPropWithInst ppmpwi) { List<CandidateFunctionMember> list = new List<CandidateFunctionMember>(); ppmpwi = null; AggregateType[] array = new AggregateType[2]; switch (GetUserDefinedBinopArgumentTypes(arg1.Type, arg2.Type, array)) { case 0: return null; case 1: GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(list, ek, array[0], arg1, arg2, fDontLift, null); break; default: { AggregateType applicableUserDefinedBinaryOperatorCandidatesInBaseTypes = GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(list, ek, array[0], arg1, arg2, fDontLift, null); GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(list, ek, array[1], arg1, arg2, fDontLift, applicableUserDefinedBinaryOperatorCandidatesInBaseTypes); break; } } if (list.IsEmpty()) return null; ExprList args = ExprFactory.CreateList(arg1, arg2); ArgInfos argInfos = new ArgInfos(); argInfos.carg = 2; FillInArgInfoFromArgList(argInfos, args); CandidateFunctionMember methAmbig; CandidateFunctionMember methAmbig2; CandidateFunctionMember candidateFunctionMember = FindBestMethod(list, null, argInfos, out methAmbig, out methAmbig2); if (candidateFunctionMember == null) throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, methAmbig.mpwi, methAmbig2.mpwi); ppmpwi = candidateFunctionMember.mpwi; if (candidateFunctionMember.ctypeLift != 0) return BindLiftedUDBinop(ek, arg1, arg2, candidateFunctionMember.params, candidateFunctionMember.mpwi); CType typeRet = TypeManager.SubstType(candidateFunctionMember.mpwi.Meth().RetType, candidateFunctionMember.mpwi.GetType()); return BindUDBinopCall(arg1, arg2, candidateFunctionMember.params, typeRet, candidateFunctionMember.mpwi); } private ExprCall BindUDBinopCall(Expr arg1, Expr arg2, TypeArray Params, CType typeRet, MethPropWithInst mpwi) { arg1 = mustConvert(arg1, Params[0]); arg2 = mustConvert(arg2, Params[1]); ExprList arguments = ExprFactory.CreateList(arg1, arg2); CheckUnsafe(arg1.Type); CheckUnsafe(arg2.Type); CheckUnsafe(typeRet); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, mpwi); ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, typeRet, arguments, memberGroup, null); exprCall.MethWithInst = new MethWithInst(mpwi); verifyMethodArgs(exprCall, mpwi.GetType()); return exprCall; } private ExprCall BindLiftedUDBinop(ExpressionKind ek, Expr arg1, Expr arg2, TypeArray Params, MethPropWithInst mpwi) { Expr expr = arg1; Expr expr2 = arg2; CType cType = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType()); TypeArray typeArray = TypeManager.SubstTypeArray(mpwi.Meth().Params, mpwi.GetType()); if (!canConvert(arg1.Type.StripNubs(), typeArray[0], CONVERTTYPE.NOUDC)) expr = mustConvert(arg1, Params[0]); if (!canConvert(arg2.Type.StripNubs(), typeArray[1], CONVERTTYPE.NOUDC)) expr2 = mustConvert(arg2, Params[1]); Expr arg3 = mustCast(expr, typeArray[0]); Expr arg4 = mustCast(expr2, typeArray[1]); CType cType2 = ((uint)(ek - 36) <= 1) ? cType : (((uint)(ek - 38) <= 3) ? cType : TypeManager.GetNullable(cType)); ExprCall expr3 = BindUDBinopCall(arg3, arg4, typeArray, cType, mpwi); ExprList arguments = ExprFactory.CreateList(expr, expr2); ExprMemberGroup memberGroup = ExprFactory.CreateMemGroup(null, mpwi); ExprCall exprCall = ExprFactory.CreateCall((EXPRFLAG)0, cType2, arguments, memberGroup, null); exprCall.MethWithInst = new MethWithInst(mpwi); switch (ek) { case ExpressionKind.Eq: exprCall.NullableCallLiftKind = NullableCallLiftKind.EqualityOperator; break; case ExpressionKind.NotEq: exprCall.NullableCallLiftKind = NullableCallLiftKind.InequalityOperator; break; default: exprCall.NullableCallLiftKind = NullableCallLiftKind.Operator; break; } exprCall.CastOfNonLiftedResultToLiftedType = mustCast(expr3, cType2, (CONVERTTYPE)0); return exprCall; } private static AggregateType GetEnumBinOpType(ExpressionKind ek, CType argType1, CType argType2, out AggregateType ppEnumType) { AggregateType aggregateType = argType1 as AggregateType; AggregateType aggregateType2 = argType2 as AggregateType; AggregateType aggregateType3 = aggregateType.IsEnumType ? aggregateType : aggregateType2; AggregateType result = aggregateType3; switch (ek) { default: if ((uint)(ek - 49) > 2) result = GetPredefindType(PredefinedType.PT_BOOL); break; case ExpressionKind.Subtract: if (aggregateType == aggregateType2) result = aggregateType3.UnderlyingEnumType; break; case ExpressionKind.Add: break; } ppEnumType = aggregateType3; return result; } private static ExprBinOp CreateBinopForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType RetType, Expr arg1, Expr arg2) { MethodSymbol method = PredefinedMembers.GetMethod(predefMeth); ExprBinOp exprBinOp = ExprFactory.CreateBinop(ek, RetType, arg1, arg2); AggregateSymbol class = method.getClass(); AggregateType aggregate = TypeManager.GetAggregate(class, TypeArray.Empty); exprBinOp.PredefinedMethodToCall = new MethWithInst(method, aggregate, null); exprBinOp.UserDefinedCallMethod = exprBinOp.PredefinedMethodToCall; return exprBinOp; } private static ExprUnaryOp CreateUnaryOpForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType pRetType, Expr pArg) { MethodSymbol method = PredefinedMembers.GetMethod(predefMeth); ExprUnaryOp exprUnaryOp = ExprFactory.CreateUnaryOp(ek, pRetType, pArg); AggregateSymbol class = method.getClass(); AggregateType aggregate = TypeManager.GetAggregate(class, TypeArray.Empty); exprUnaryOp.PredefinedMethodToCall = new MethWithInst(method, aggregate, null); exprUnaryOp.UserDefinedCallMethod = exprUnaryOp.PredefinedMethodToCall; return exprUnaryOp; } } }