//------------------------------------------------------------ // FUNCBREC.BindNubValue // /// <summary> /// Create an expr for exprSrc.Value where exprSrc->type is a NUBSYM. /// </summary> /// <param name="treeNode"></param> /// <param name="srcExpr"></param> /// <returns></returns> //------------------------------------------------------------ private EXPR BindNubValue(BASENODE treeNode, EXPR srcExpr) { DebugUtil.Assert(srcExpr != null && srcExpr.TypeSym.IsNUBSYM); // For new T?(x), the answer is x. if (IsNubCtor(srcExpr)) { DebugUtil.Assert( (srcExpr as EXPRCALL).ArgumentsExpr != null && (srcExpr as EXPRCALL).ArgumentsExpr.Kind != EXPRKIND.LIST); return((srcExpr as EXPRCALL).ArgumentsExpr); } TYPESYM baseTypeSym = (srcExpr.TypeSym as NUBSYM).BaseTypeSym; AGGTYPESYM ats = (srcExpr.TypeSym as NUBSYM).GetAggTypeSym(); if (ats == null) { return(NewError(treeNode, baseTypeSym)); } compiler.EnsureState(ats, AggStateEnum.Prepared); PROPSYM propertySym = compiler.MainSymbolManager.NullableValuePropertySym; if (propertySym == null) { string name = compiler.NameManager.GetPredefinedName(PREDEFNAME.CAP_VALUE); propertySym = compiler.MainSymbolManager.LookupAggMember( name, ats.GetAggregate(), SYMBMASK.PROPSYM) as PROPSYM; if (propertySym == null || propertySym.IsStatic || propertySym.Access != ACCESS.PUBLIC || propertySym.ParameterTypes.Count > 0 || !propertySym.ReturnTypeSym.IsTYVARSYM || propertySym.GetMethodSym == null) { compiler.Error( treeNode, CSCERRID.ERR_MissingPredefinedMember, new ErrArg(ats), new ErrArg(name)); return(NewError(treeNode, baseTypeSym)); } compiler.MainSymbolManager.NullableValuePropertySym = propertySym; } CheckFieldUse(srcExpr, true); EXPRPROP propertyExpr = NewExpr(treeNode, EXPRKIND.PROP, baseTypeSym) as EXPRPROP; propertyExpr.SlotPropWithType.Set(propertySym, ats); propertyExpr.GetMethodWithType.Set(propertySym.GetMethodSym, ats); propertyExpr.ArgumentsExpr = null; propertyExpr.ObjectExpr = srcExpr; return(propertyExpr); }
//------------------------------------------------------------ // MetaDataHelper.AddTypeModifiers // /// <summary> /// appends array and ptr modifiers /// </summary> /// <param name="typeSym"></param> /// <param name="strBuilder"></param> //------------------------------------------------------------ protected void AddTypeModifiers(TYPESYM typeSym, StringBuilder strBuilder) { switch (typeSym.Kind) { case SYMKIND.AGGTYPESYM: case SYMKIND.TYVARSYM: case SYMKIND.ERRORSYM: case SYMKIND.NUBSYM: break; case SYMKIND.ARRAYSYM: // NOTE: In C# a 2-dim array of 1-dim array of int is int[,][]. // This produces int[][,] as metadata requires. AddTypeModifiers((typeSym as ARRAYSYM).ElementTypeSym, strBuilder); strBuilder.Append('['); for (int i = 1; i < (typeSym as ARRAYSYM).Rank; ++i) { strBuilder.Append(','); } strBuilder.Append(']'); break; case SYMKIND.PTRSYM: AddTypeModifiers((typeSym as PTRSYM).BaseTypeSym, strBuilder); strBuilder.Append('*'); break; default: DebugUtil.Assert(false, "Unknown symbol typeSym"); break; } }
//------------------------------------------------------------ // CreateGetTypeFromHandleMethodSym // /// <summary> /// <para>Defined in FuncBindUtil.cs</para> /// </summary> /// <param name="treeNode"></param> /// <returns></returns> //------------------------------------------------------------ internal METHSYM CreateGetTypeFromHandleMethodSym(BASENODE treeNode) { if (GetTypeFromHandleMethodSym != null) { return(GetTypeFromHandleMethodSym); } // System.RuntimeTypeHandle TYPESYM handleTypeSym = this.GetRequiredPredefinedType(PREDEFTYPE.TYPEHANDLE); DebugUtil.Assert(handleTypeSym != null); TypeArray paramArray = new TypeArray(); paramArray.Add(handleTypeSym); paramArray = Compiler.MainSymbolManager.AllocParams(paramArray); GetTypeFromHandleMethodSym = FindPredefMeth( treeNode, PREDEFNAME.GETTYPEFROMHANDLE, this.GetRequiredPredefinedType(PREDEFTYPE.TYPE), paramArray, true, MemLookFlagsEnum.None); DebugUtil.Assert(GetTypeFromHandleMethodSym != null); return(GetTypeFromHandleMethodSym); }
//------------------------------------------------------------ // FUNCBREC.BindImplicitlyTypedArrayInitCore // /// <summary></summary> /// <param name="treeUnOpNode"></param> /// <param name="elementTypeSym"></param> /// <param name="dimList"></param> /// <param name="dimIndex"></param> /// <param name="topArgList"></param> //------------------------------------------------------------ internal void BindImplicitlyTypedArrayInitCore( UNOPNODE treeUnOpNode, ref TYPESYM elementTypeSym, List <int> dimList, int dimIndex, ref EXPR topArgList) { int count = 0; EXPR lastArgList = null; BASENODE node = treeUnOpNode.Operand; while (node != null) { BASENODE itemNode; if (node.Kind == NODEKIND.LIST) { itemNode = node.AsLIST.Operand1.AsBASE; node = node.AsLIST.Operand2; } else { itemNode = node.AsBASE; node = null; } count++; EXPR expr = BindExpr(itemNode, BindFlagsEnum.RValueRequired); if (elementTypeSym == null || elementTypeSym.Kind == SYMKIND.IMPLICITTYPESYM) { elementTypeSym = expr.TypeSym; } else if (CanConvert(elementTypeSym, expr.TypeSym, ConvertTypeEnum.STANDARD)) { elementTypeSym = expr.TypeSym; } else if (!CanConvert(expr.TypeSym, elementTypeSym, ConvertTypeEnum.STANDARD)) { // do nothing here. } NewList(expr, ref topArgList, ref lastArgList); //exprList.Add(expr); } if (dimList[dimIndex] != -1) { if (dimList[dimIndex] != count) { Compiler.Error(treeUnOpNode, CSCERRID.ERR_InvalidArray); } } else { dimList[dimIndex] = count; } }
//------------------------------------------------------------ // CLSDREC.CreateBackField // /// <summary></summary> /// <param name="aggSym"></param> /// <param name="propName"></param> //------------------------------------------------------------ private MEMBVARSYM CreateBackField( PROPERTYNODE propNode, string propName, TYPESYM propTypeSym, AGGSYM aggSym, AGGDECLSYM aggDeclSym) { DebugUtil.Assert(aggSym.IsClass || aggSym.IsStruct); string backFieldName = GenerateBackFieldName(propName); NODEFLAGS propFlags = propNode.Flags; MEMBVARSYM backFieldSym = Compiler.MainSymbolManager.CreateMembVar( backFieldName, aggSym, aggDeclSym); backFieldSym.TypeSym = propTypeSym; backFieldSym.ParseTreeNode = null; backFieldSym.IsAssigned = true; NODEFLAGS allowableFlags = aggSym.AllowableMemberAccess() | NODEFLAGS.MOD_UNSAFE | NODEFLAGS.MOD_NEW | NODEFLAGS.MOD_STATIC; backFieldSym.IsUnsafe = (aggDeclSym.IsUnsafe || (propFlags & NODEFLAGS.MOD_UNSAFE) != 0); if ((propFlags & NODEFLAGS.MOD_ABSTRACT) != 0) { DebugUtil.Assert((allowableFlags & NODEFLAGS.MOD_ABSTRACT) == 0); Compiler.ErrorRef(null, CSCERRID.ERR_AbstractField, new ErrArgRef(backFieldSym)); //flags &= ~NODEFLAGS.MOD_ABSTRACT; } backFieldSym.Access = ACCESS.PRIVATE; // GetAccessFromFlags(aggSym, allowableFlags, flags); if ((propFlags & NODEFLAGS.MOD_STATIC) != 0) { backFieldSym.IsStatic = true; } CheckForProtectedInSealed(backFieldSym); // Check that the field type is as accessible as the field itself. CheckConstituentVisibility(backFieldSym, propTypeSym, CSCERRID.ERR_BadVisFieldType); return(backFieldSym); }
//------------------------------------------------------------ // FUNCBREC.BindImplicitlyTypedArrayInit // /// <summary></summary> /// <param name="treeNode"></param> /// <param name="arrayTypeSym"></param> /// <param name="argListExpr"></param> /// <returns></returns> //------------------------------------------------------------ internal EXPR BindImplicitlyTypedArrayInit( UNOPNODE treeNode, ref TYPESYM arrayTypeSym) { EXPRARRINIT arrayInitExpr = NewExpr( treeNode, EXPRKIND.ARRINIT, null) as EXPRARRINIT; arrayInitExpr.Flags |= EXPRFLAG.CANTBENULL; TYPESYM elementTypeSym = null; arrayInitExpr.DimSizes = new List <int>(); arrayInitExpr.DimSizes.Add(-1); //bool isConstant = // elementTypeSym.IsSimpleType() && // BSYMMGR.GetAttrArgSize(elementTypeSym.GetPredefType()) > 0; int nonConstCount = 0; int constCount = 0; bool hasSideEffects = false; BindImplicitlyTypedArrayInitCore( treeNode, ref elementTypeSym, arrayInitExpr.DimSizes, 0, ref arrayInitExpr.ArgumentsExpr); arrayTypeSym = Compiler.MainSymbolManager.GetArray( elementTypeSym, 1, null); arrayInitExpr.TypeSym = arrayTypeSym; BindImplicitlyTypedArrayInitConvert( elementTypeSym, arrayInitExpr.DimSizes, 0, ref arrayInitExpr.ArgumentsExpr, ref nonConstCount, ref constCount, ref hasSideEffects); return(arrayInitExpr); }
//------------------------------------------------------------ // FUNCBREC.BindNubGetValOrDef // /// <summary> /// Create an expr for exprSrc.GetValueOrDefault() /// where exprSrc->type is a NUBSYM. /// </summary> /// <param name="treeNode"></param> /// <param name="srcExpr"></param> /// <returns></returns> //------------------------------------------------------------ private EXPR BindNubGetValOrDef(BASENODE treeNode, EXPR srcExpr) { DebugUtil.Assert(srcExpr != null && srcExpr.TypeSym.IsNUBSYM); TYPESYM baseTypeSym = (srcExpr.TypeSym as NUBSYM).BaseTypeSym; // If srcExpr is null, just return the appropriate default value. if (srcExpr.GetConst() != null) { return(AddSideEffects(treeNode, NewExprZero(treeNode, baseTypeSym), srcExpr, true, true)); } // For new T?(x), the answer is x. if (IsNubCtor(srcExpr)) { DebugUtil.Assert( (srcExpr as EXPRCALL).ArgumentsExpr != null && (srcExpr as EXPRCALL).ArgumentsExpr.Kind != EXPRKIND.LIST); return((srcExpr as EXPRCALL).ArgumentsExpr); } AGGTYPESYM aggTypeSym = (srcExpr.TypeSym as NUBSYM).GetAggTypeSym(); if (aggTypeSym == null) { return(NewError(treeNode, baseTypeSym)); } Compiler.EnsureState(aggTypeSym, AggStateEnum.Prepared); METHSYM methSym = EnsureNubGetValOrDef(treeNode); if (methSym == null) { return(NewError(treeNode, baseTypeSym)); } CheckFieldUse(srcExpr, true); EXPRCALL resExpr = NewExpr(treeNode, EXPRKIND.CALL, baseTypeSym) as EXPRCALL; resExpr.MethodWithInst.Set(methSym, aggTypeSym, BSYMMGR.EmptyTypeArray); resExpr.ArgumentsExpr = null; resExpr.ObjectExpr = srcExpr; return(resExpr); }
//------------------------------------------------------------ // FUNCBREC.BindNubOpRes (1) // /// <summary> /// <para>Combine the condition and value.</para> /// <para>(In sscli, warOnNull has the default value false.)</para> /// </summary> /// <param name="treeNode"></param> /// <param name="nubSym"></param> /// <param name="dstTypeSym"></param> /// <param name="valueExpr"></param> /// <param name="nubInfo"></param> /// <param name="warnOnNull"></param> /// <returns></returns> //------------------------------------------------------------ private EXPR BindNubOpRes( BASENODE treeNode, NUBSYM nubSym, TYPESYM dstTypeSym, EXPR valueExpr, ref NubInfo nubInfo, bool warnOnNull) // = false { if (nubInfo.FAlwaysNull() && warnOnNull) { Compiler.Error(treeNode, CSCERRID.WRN_AlwaysNull, new ErrArg(nubSym)); } return(BindNubOpRes( treeNode, dstTypeSym, valueExpr, NewExprZero(treeNode, dstTypeSym.IsNUBSYM ? dstTypeSym : nubSym), ref nubInfo)); }
//------------------------------------------------------------ // FUNCBREC.BindTypeOf // /// <summary> /// <para>Defined in FuncBindUtil.cs</para> /// </summary> /// <param name="treeNode"></param> /// <returns></returns> //------------------------------------------------------------ private EXPRTYPEOF BindTypeOf(TYPESYM typeSym) { DebugUtil.Assert(typeSym != null); if (typeSym.IsERRORSYM) { goto LERROR; } if (typeSym == GetVoidType()) { typeSym = this.GetRequiredPredefinedType(PREDEFTYPE.SYSTEMVOID); } EXPRTYPEOF typeofExpr = null; typeofExpr = NewExpr( treeNode, EXPRKIND.TYPEOF, this.GetRequiredPredefinedType(PREDEFTYPE.TYPE)) as EXPRTYPEOF; typeofExpr.MethodSym = CreateGetTypeFromHandleMethodSym(null); typeofExpr.SourceTypeSym = typeSym; #if false if (operandNode.Kind == NODEKIND.OPENTYPE) { DebugUtil.Assert( typeSym.IsAGGTYPESYM && (typeSym as AGGTYPESYM).AllTypeArguments.Count > 0 && (typeSym as AGGTYPESYM).AllTypeArguments[(typeSym as AGGTYPESYM).AllTypeArguments.Count - 1].IsUNITSYM); rval.Flags |= EXPRFLAG.OPENTYPE; } #endif typeofExpr.Flags |= EXPRFLAG.CANTBENULL; return(typeofExpr); LERROR: //return NewError(treeNode, this.GetRequiredPredefinedType(PREDEFTYPE.TYPE)); return(null); }
//------------------------------------------------------------ // CLSDREC.CheckFlagsAndSigOfPartialMethod // /// <summary></summary> /// <param name="nodeFlags"></param> /// <param name="methodSym"></param> /// <returns></returns> //------------------------------------------------------------ internal void CheckFlagsAndSigOfPartialMethod( BASENODE treeNode, NODEFLAGS nodeFlags, METHSYM methodSym) { const NODEFLAGS forbidden = 0 | NODEFLAGS.MOD_ABSTRACT | NODEFLAGS.MOD_NEW | NODEFLAGS.MOD_OVERRIDE | NODEFLAGS.MOD_PRIVATE | NODEFLAGS.MOD_PROTECTED | NODEFLAGS.MOD_INTERNAL | NODEFLAGS.MOD_PUBLIC | NODEFLAGS.MOD_SEALED | NODEFLAGS.MOD_VIRTUAL | NODEFLAGS.MOD_EXTERN; if ((nodeFlags & forbidden) != 0) { Compiler.Error(treeNode, CSCERRID.ERR_BadModifierForPartialMethod); } TypeArray paramTypes = methodSym.ParameterTypes; if (paramTypes != null && paramTypes.Count > 0) { for (int i = 0; i < paramTypes.Count; ++i) { TYPESYM typeSym = paramTypes[i]; if (typeSym.Kind == SYMKIND.PARAMMODSYM && (typeSym as PARAMMODSYM).IsOut) { Compiler.Error( treeNode, CSCERRID.ERR_PartialMethodHasOutParameter); } } } }
//------------------------------------------------------------ // FUNCBREC.CreateNewLocVarSym // /// <summary>Increments the following values: /// FUNCBREC.localCount, /// FUNCBREC.unreferencedVarCount and /// FUNCBREC.uninitedVarCount. /// And sets LOCVARSYM.LocSlotInfo. /// </summary> /// <param name="name"></param> /// <param name="typeSym"></param> /// <param name="parentSym"></param> /// <returns></returns> //------------------------------------------------------------ internal LOCVARSYM CreateNewLocVarSym( string name, TYPESYM typeSym, PARENTSYM parentSym) { SYM sym = Compiler.LocalSymbolManager.LookupLocalSym( name, parentSym, SYMBMASK.LOCVARSYM); if (sym != null) { return(sym as LOCVARSYM); } LOCVARSYM locSym = Compiler.LocalSymbolManager.CreateLocalSym( SYMKIND.LOCVARSYM, name, parentSym) as LOCVARSYM; locSym.TypeSym = typeSym; StoreInCache(null, name, locSym, null, true); ++this.localCount; if (this.localCount > 0xffff) { Compiler.Error(treeNode, CSCERRID.ERR_TooManyLocals); } ++this.unreferencedVarCount; locSym.LocSlotInfo.SetJbitDefAssg(this.uninitedVarCount + 1); int cbit = FlowChecker.GetCbit(Compiler, locSym.TypeSym); this.uninitedVarCount += cbit; return(locSym); }
//------------------------------------------------------------ // FUNCBREC.BindNubOpRes (2) // /// <summary> /// Combine the condition and value. /// </summary> /// <param name="treeNode"></param> /// <param name="dstTypeSym"></param> /// <param name="valueExpr"></param> /// <param name="nullExpr"></param> /// <param name="nubInfo"></param> /// <returns></returns> //------------------------------------------------------------ private EXPR BindNubOpRes( BASENODE treeNode, TYPESYM dstTypeSym, EXPR valueExpr, EXPR nullExpr, ref NubInfo nubInfo) { EXPR resExpr; nullExpr = MustConvert(nullExpr, dstTypeSym, 0); valueExpr = MustConvert(valueExpr, dstTypeSym, 0); if (nubInfo.FAlwaysNonNull()) { // Don't need nullExpr and there aren't any temps. resExpr = valueExpr; } else if (nubInfo.FAlwaysNull()) { // Don't need valueExpr but do need side effects. resExpr = BindNubAddTmps(treeNode, nullExpr, ref nubInfo); } else { DebugUtil.Assert(nubInfo.CombinedConditionExpr != null); resExpr = BindQMark( treeNode, nubInfo.CombinedConditionExpr, MustConvert(valueExpr, dstTypeSym, 0), nullExpr, false); resExpr = BindNubAddTmps(treeNode, resExpr, ref nubInfo); } return(resExpr); }
//------------------------------------------------------------ // FUNCBREC.BindNubHasValue // /// <summary> /// <para>Create an expr for exprSrc.HasValue where exprSrc->type is a NUBSYM.</para> /// <para>If fCheckTrue is false, invert the result.</para> /// <para>(In sscli, checkTrue has the default value true.)</para> /// </summary> /// <param name="treeNode"></param> /// <param name="srcExpr"></param> /// <param name="checkTrue"></param> /// <returns></returns> //------------------------------------------------------------ private EXPR BindNubHasValue( BASENODE treeNode, EXPR srcExpr, bool checkTrue) // = true { DebugUtil.Assert(srcExpr != null && srcExpr.TypeSym.IsNUBSYM); TYPESYM boolTypeSym = GetRequiredPredefinedType(PREDEFTYPE.BOOL); // When srcExpr is a null, the result is false if (srcExpr.GetConst() != null) { return(AddSideEffects( treeNode, NewExprConstant(treeNode, boolTypeSym, new ConstValInit(!checkTrue)), srcExpr, true, true)); } // For new T?(x), the answer is true. if (IsNubCtor(srcExpr)) { return(AddSideEffects( treeNode, NewExprConstant(treeNode, boolTypeSym, new ConstValInit(checkTrue)), StripNubCtor(srcExpr), true, true)); } AGGTYPESYM aggTypeSym = (srcExpr.TypeSym as NUBSYM).GetAggTypeSym(); if (aggTypeSym == null) { return(NewError(treeNode, boolTypeSym)); } Compiler.EnsureState(aggTypeSym, AggStateEnum.Prepared); PROPSYM propSym = EnsureNubHasValue(treeNode); if (propSym == null) { return(NewError(treeNode, boolTypeSym)); } CheckFieldUse(srcExpr, true); EXPRPROP resExpr = NewExpr(treeNode, EXPRKIND.PROP, boolTypeSym) as EXPRPROP; resExpr.SlotPropWithType.Set(propSym, aggTypeSym); resExpr.GetMethodWithType.Set(propSym.GetMethodSym, aggTypeSym); resExpr.ArgumentsExpr = null; resExpr.ObjectExpr = srcExpr; if (checkTrue) { return(resExpr); } return(NewExprBinop(treeNode, EXPRKIND.LOGNOT, resExpr.TypeSym, resExpr, null)); }
//------------------------------------------------------------ // FUNCBREC.BindNubConversion // // Called by bindImplicitConversion when the destination type is Nullable<T>. The following // conversions are handled by this method: // // * For S in { object, ValueType, interfaces implemented by underlying type} there is an explicit // unboxing conversion S => T? // * System.Enum => T? there is an unboxing conversion if T is an enum type // * null => T? implemented as default(T?) // // * Implicit T?* => T?+ implemented by either wrapping or calling GetValueOrDefault the // appropriate number of times. // * If imp/exp S => T then imp/exp S => T?+ implemented by converting to T then wrapping the // appropriate number of times. // * If imp/exp S => T then imp/exp S?+ => T?+ implemented by calling GetValueOrDefault (m-1) times // then calling HasValue, producing a null if it returns false, otherwise calling Value, // converting to T then wrapping the appropriate number of times. // // The 3 rules above can be summarized with the following recursive rules: // // * If imp/exp S => T? then imp/exp S? => T? implemented as // qs.HasValue ? (T?)(qs.Value) : default(T?) // * If imp/exp S => T then imp/exp S => T? implemented as new T?((T)s) // // This method also handles calling bindUserDefinedConverion. This method does NOT handle // the following conversions: // // * Implicit boxing conversion from S? to { object, ValueType, Enum, ifaces implemented by S }. (Handled by bindImplicitConversion.) // * If imp/exp S => T then explicit S?+ => T implemented by calling Value the appropriate number // of times. (Handled by bindExplicitConversion.) // // The recursive equivalent is: // // * If imp/exp S => T and T is not nullable then explicit S? => T implemented as qs.Value // // Some nullable conversion are NOT standard conversions. In particular, if S => T is implicit // then S? => T is not standard. Similarly if S => T is not implicit then S => T? is not standard. // /// <summary></summary> /// <param name="treeNode"></param> /// <param name="srcExpr"></param> /// <param name="srcTypeSym"></param> /// <param name="dstNubSym"></param> /// <param name="dstExpr"></param> /// <param name="flags"></param> /// <returns></returns> //------------------------------------------------------------ private bool BindNubConversion( BASENODE treeNode, EXPR srcExpr, TYPESYM srcTypeSym, NUBSYM dstNubSym, ref EXPR dstExpr, ConvertTypeEnum flags) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! DebugUtil.Assert((~flags & (ConvertTypeEnum.STANDARD | ConvertTypeEnum.ISEXPLICIT)) != 0); DebugUtil.Assert(srcExpr == null || srcExpr.TypeSym == srcTypeSym); DebugUtil.Assert(dstExpr == null || srcExpr != null); DebugUtil.Assert(srcTypeSym != dstNubSym); // bindImplicitConversion should have taken care of this already. AGGTYPESYM dstAggTypeSym = dstNubSym.GetAggTypeSym(); if (dstAggTypeSym == null) { return(false); } // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (Compiler.IsBaseType(dstNubSym.BaseTypeSym, srcTypeSym) && !FWrappingConv(srcTypeSym, dstNubSym)) { // These should be different! Fix the caller if srcTypeSym is an AGGTYPESYM of Nullable. DebugUtil.Assert(dstAggTypeSym != srcTypeSym); // srcTypeSym is a base type of the destination nullable type so there is an explicit // unboxing conversion. if ((flags & ConvertTypeEnum.ISEXPLICIT) == 0) { return(false); } return(BindSimpleCast(treeNode, srcExpr, dstNubSym, ref dstExpr, EXPRFLAG.UNBOX)); } int dstNubStripCount; int srcNubStripCount; TYPESYM dstBaseTypeSym = dstNubSym.StripNubs(out dstNubStripCount); TYPESYM srcBaseTypeSym = srcTypeSym.StripNubs(out srcNubStripCount); bindNubConversion_Convert fnConvert; EXPR expr = null; // temp if ((flags & ConvertTypeEnum.ISEXPLICIT) != 0) { fnConvert = new bindNubConversion_Convert(BindExplicitConversion); } else { fnConvert = new bindNubConversion_Convert(BindImplicitConversion); } //bool (FUNCBREC::*pfn)(BASENODE *, EXPR *, TYPESYM *, TYPESYM *, EXPR **, uint) = // (flags & ISEXPLICIT) ? &FUNCBREC::bindExplicitConversion : &FUNCBREC::bindImplicitConversion; if (srcNubStripCount == 0) { DebugUtil.Assert(srcTypeSym == srcBaseTypeSym); // The null type can be implicitly converted to T? as the default value. if (srcTypeSym.IsNULLSYM) { dstExpr = AddSideEffects(treeNode, NewExprZero(treeNode, dstNubSym), srcExpr, true, true); return(true); } EXPR tempExpr = srcExpr; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (srcTypeSym == dstBaseTypeSym || fnConvert( treeNode, srcExpr, srcTypeSym, dstBaseTypeSym, ref tempExpr, flags | ConvertTypeEnum.NOUDC)) { // srcTypeSym is not nullable so just wrap the required number of times. for (int i = 0; i < dstNubStripCount; i++) { tempExpr = BindNubNew(treeNode, tempExpr); } DebugUtil.Assert(tempExpr.TypeSym == dstNubSym); dstExpr = tempExpr; return(true); } // No builtin conversion. Maybe there is a user defined conversion.... return( (flags & ConvertTypeEnum.NOUDC) == 0 && BindUserDefinedConversion( treeNode, srcExpr, srcTypeSym, dstNubSym, ref dstExpr, (flags & ConvertTypeEnum.ISEXPLICIT) == 0)); } // Both are Nullable so there is only a conversion if there is a conversion between the base types. // That is, if there is an implicit/explicit S => T then there is an implicit/explicit S?+ => T?+. if (srcBaseTypeSym != dstBaseTypeSym && !fnConvert(treeNode, null, srcBaseTypeSym, dstBaseTypeSym, ref expr, flags | ConvertTypeEnum.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return( (flags & ConvertTypeEnum.NOUDC) == 0 && BindUserDefinedConversion( treeNode, srcExpr, srcTypeSym, dstNubSym, ref dstExpr, (flags & ConvertTypeEnum.ISEXPLICIT) == 0)); } // We need to go all the way down to the base types, do the conversion, then come all the way back up. EXPR valExpr; NubInfo nubInfo = new NubInfo(); BindNubCondValBin( treeNode, srcExpr, null, ref nubInfo, LiftFlagsEnum.LiftBoth); valExpr = nubInfo.Val(0); DebugUtil.Assert(valExpr.TypeSym == srcBaseTypeSym); if (!fnConvert( treeNode, valExpr, valExpr.TypeSym, dstBaseTypeSym, ref valExpr, flags | ConvertTypeEnum.NOUDC)) { DebugUtil.Assert(false, "bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } for (int i = 0; i < dstNubStripCount; i++) { valExpr = BindNubNew(treeNode, valExpr); } DebugUtil.Assert(valExpr.TypeSym == dstNubSym); dstExpr = BindNubOpRes(treeNode, dstNubSym, dstNubSym, valExpr, ref nubInfo, false); return(true); }
//------------------------------------------------------------ // FUNCBREC.BindCollectionInitializer // /// <summary></summary> /// <param name="newNode"></param> /// <param name="typeSym"></param> /// <param name="locVarSym"></param> /// <param name="objectExpr"></param> /// <param name="builder"></param> /// <returns></returns> //------------------------------------------------------------ internal EXPR BindCollectionInitializer( NEWNODE newNode, BASENODE elementsNode, TYPESYM typeSym, LOCVARSYM locVarSym, EXPR leftExpr, EXPR rightExpr, StatementListBuilder builder) { DebugUtil.Assert(newNode != null && typeSym != null && builder != null); DebugUtil.Assert(locVarSym != null || leftExpr != null || rightExpr != null); string addMethName = Compiler.NameManager.GetPredefinedName(PREDEFNAME.ADD); //-------------------------------------------------------- // typeSym should implement IEnumerable. //-------------------------------------------------------- AGGTYPESYM enumerableSym = HasIEnumerable(typeSym); if (enumerableSym == null) { Compiler.Error( newNode.TypeNode, CSCERRID.ERR_CollectInitRequiresIEnumerable, new ErrArg(typeSym)); return(rightExpr); } TYPESYM paramTypeSym = null; TypeArray typeArgs = enumerableSym.TypeArguments; if (typeArgs != null && typeArgs.Count > 0) { DebugUtil.Assert(typeArgs.Count == 1); paramTypeSym = typeArgs[0]; } else { paramTypeSym = Compiler.GetReqPredefAgg(PREDEFTYPE.OBJECT, true).GetThisType(); if (typeArgs == null) { typeArgs = new TypeArray(); } typeArgs.Add(paramTypeSym); typeArgs = Compiler.MainSymbolManager.AllocParams(typeArgs); } BindFlagsEnum bindFlags = BindFlagsEnum.RValueRequired; string localFormat = "<{0}><{1}>__local"; //-------------------------------------------------------- // Bind the local variable. //-------------------------------------------------------- if (leftExpr == null) { if (locVarSym == null) { string locName = String.Format(localFormat, typeSym.Name, (this.localCount)++); locVarSym = Compiler.LocalSymbolManager.CreateLocalSym( SYMKIND.LOCVARSYM, locName, this.currentScopeSym) as LOCVARSYM; locVarSym.TypeSym = typeSym; locVarSym.LocSlotInfo.HasInit = true; locVarSym.DeclTreeNode = newNode; StoreInCache(newNode, locName, locVarSym, null, true); } leftExpr = BindToLocal( newNode, locVarSym, bindFlags | BindFlagsEnum.MemberSet); } //-------------------------------------------------------- // If objectExpr is not null, assign it to the local variable. //-------------------------------------------------------- if (rightExpr != null) { EXPR assignLocExpr = BindAssignment( newNode, leftExpr, rightExpr, false); builder.Add(SetNodeStmt(newNode, MakeStmt(newNode, assignLocExpr, 0))); } //-------------------------------------------------------- // Get "Add" method. //-------------------------------------------------------- MemberLookup mem = new MemberLookup(); if (!mem.Lookup( Compiler, typeSym, leftExpr, this.parentDeclSym, addMethName, 0, MemLookFlagsEnum.UserCallable)) { Compiler.Error( newNode.TypeNode, CSCERRID.ERR_NoSuchMember, new ErrArg(typeSym), new ErrArg("Add")); return(NewError(newNode, null)); } if (mem.FirstSym == null || !mem.FirstSym.IsMETHSYM) { return(NewError(newNode, null)); } TypeArray typeGroup = mem.GetAllTypes(); EXPRMEMGRP grpExpr = NewExpr( newNode, EXPRKIND.MEMGRP, Compiler.MainSymbolManager.MethodGroupTypeSym) as EXPRMEMGRP; grpExpr.Name = addMethName; grpExpr.SymKind = SYMKIND.METHSYM; grpExpr.TypeArguments = BSYMMGR.EmptyTypeArray; grpExpr.ParentTypeSym = typeSym; grpExpr.MethPropSym = null; grpExpr.ObjectExpr = leftExpr; grpExpr.ContainingTypeArray = typeGroup; grpExpr.Flags |= EXPRFLAG.USERCALLABLE; //-------------------------------------------------------- // Add each value. //-------------------------------------------------------- DebugUtil.Assert(newNode.InitialNode != null); #if false BASENODE node = null; switch (newNode.InitialNode.Kind) { case NODEKIND.DECLSTMT: node = (newNode.InitialNode as DECLSTMTNODE).VariablesNode; break; case NODEKIND.UNOP: node = (newNode.InitialNode as UNOPNODE).Operand; break; default: DebugUtil.Assert(false); break; } #endif BASENODE node = elementsNode; while (node != null) { BASENODE elementNode; if (node.Kind == NODEKIND.LIST) { elementNode = node.AsLIST.Operand1; node = node.AsLIST.Operand2; } else { elementNode = node; node = null; } //---------------------------------------------------- // Bind the elements //---------------------------------------------------- EXPR elementExpr = BindExpr( elementNode, BindFlagsEnum.RValueRequired); //---------------------------------------------------- // Add the elements //---------------------------------------------------- EXPR addExpr = BindGrpToArgs(newNode, bindFlags, grpExpr, elementExpr); if (addExpr != null) { builder.Add(SetNodeStmt(newNode, MakeStmt(newNode, addExpr, 0))); } } return(leftExpr); }
//------------------------------------------------------------ // FUNCBREC.BindObjectInitializer // /// <summary></summary> /// <param name="newNode"></param> /// <param name="typeSym"></param> /// <param name="locVarSym"></param> /// <param name="objectExpr"></param> /// <param name="builder"></param> /// <returns></returns> //------------------------------------------------------------ internal EXPR BindObjectInitializer( NEWNODE newNode, TYPESYM typeSym, LOCVARSYM locVarSym, EXPR objectExpr, StatementListBuilder builder) { DebugUtil.Assert(newNode != null && typeSym != null && builder != null); DebugUtil.Assert( (locVarSym != null && objectExpr == null) || (locVarSym == null && objectExpr != null)); BindFlagsEnum bindFlags = BindFlagsEnum.RValueRequired; string localFormat = "<{0}><{1}>__local"; //-------------------------------------------------------- // Bind the local variable. //-------------------------------------------------------- if (locVarSym == null) { string typeName = typeSym.IsAGGTYPESYM ? (typeSym as AGGTYPESYM).GetAggregate().Name : typeSym.Name; string locName = String.Format(localFormat, typeName, (this.localCount)++); locVarSym = Compiler.LocalSymbolManager.CreateLocalSym( SYMKIND.LOCVARSYM, locName, this.currentScopeSym) as LOCVARSYM; locVarSym.TypeSym = typeSym; locVarSym.LocSlotInfo.HasInit = true; locVarSym.DeclTreeNode = newNode; StoreInCache(newNode, locName, locVarSym, null, true); } EXPR locVarExpr = BindToLocal( newNode, locVarSym, bindFlags | BindFlagsEnum.MemberSet); //-------------------------------------------------------- // If objectExpr is not null, assign it to the local variable. //-------------------------------------------------------- if (objectExpr != null) { EXPR assignLocExpr = BindAssignment( newNode, locVarExpr, objectExpr, false); builder.Add(SetNodeStmt(newNode, MakeStmt(newNode, assignLocExpr, 0))); } //-------------------------------------------------------- // Assign each value. //-------------------------------------------------------- DECLSTMTNODE decNode = newNode.InitialNode as DECLSTMTNODE; DebugUtil.Assert(decNode != null); BASENODE node = decNode.VariablesNode; while (node != null) { VARDECLNODE varDecl; if (node.Kind == NODEKIND.LIST) { varDecl = node.AsLIST.Operand1 as VARDECLNODE; node = node.AsLIST.Operand2; } else { varDecl = node as VARDECLNODE; node = null; } BINOPNODE assignNode = varDecl.ArgumentsNode as BINOPNODE; if (assignNode == null || assignNode.Operator != OPERATOR.ASSIGN || assignNode.Operand1 == null || assignNode.Operand1.Kind != NODEKIND.NAME || assignNode.Operand2 == null) { continue; } //---------------------------------------------------- // LHS //---------------------------------------------------- NAMENODE nameNode = assignNode.Operand1 as NAMENODE; DebugUtil.Assert(nameNode != null); bindFlags = BindFlagsEnum.MemberSet; MemberLookup mem = new MemberLookup(); EXPR leftExpr = null; if (mem.Lookup( Compiler, typeSym, locVarExpr, this.parentDeclSym, nameNode.Name, 0, MemLookFlagsEnum.UserCallable)) { SymWithType swt = mem.FirstSymWithType; DebugUtil.Assert(swt != null && swt.IsNotNull); switch (swt.Sym.Kind) { case SYMKIND.MEMBVARSYM: leftExpr = BindToField( assignNode, locVarExpr, FieldWithType.Convert(swt), bindFlags); break; case SYMKIND.PROPSYM: leftExpr = BindToProperty( assignNode, locVarExpr, PropWithType.Convert(swt), bindFlags, null, null); break; default: leftExpr = NewError(nameNode, null); break; } } else { mem.ReportErrors(nameNode); leftExpr = NewError(nameNode, null); } //---------------------------------------------------- // Collection initializer //---------------------------------------------------- if (assignNode.Operand2.Kind == NODEKIND.ARRAYINIT) { if (!leftExpr.TypeSym.IsARRAYSYM) { BindCollectionInitializer( newNode, (assignNode.Operand2 as UNOPNODE).Operand, leftExpr.TypeSym, //typeSym, null, //locVarSym, leftExpr, null, builder); continue; } } //---------------------------------------------------- // RHS //---------------------------------------------------- EXPR rightExpr = BindExpr( assignNode.Operand2, BindFlagsEnum.RValueRequired); //---------------------------------------------------- // Assign //---------------------------------------------------- EXPR assignExpr = BindAssignment( assignNode, leftExpr, rightExpr, false); builder.Add(SetNodeStmt(decNode, MakeStmt(decNode, assignExpr, 0))); } return(locVarExpr); }
//------------------------------------------------------------ // ReflectionUtil.IsTypeBuilderInstruction // /// <summary></summary> /// <param name="typeSym"></param> /// <returns></returns> //------------------------------------------------------------ internal static bool IsTypeBuilderInstruction(TYPESYM typeSym) { if (typeSym == null) { return(false); } Type type = null; int count = 0; int index = 0; switch (typeSym.Kind) { //---------------------------------------------------- // AGGTYPESYM //---------------------------------------------------- case SYMKIND.AGGTYPESYM: AGGTYPESYM ats = typeSym as AGGTYPESYM; DebugUtil.Assert(ats != null); if (ats.AllTypeArguments == null || ats.AllTypeArguments.Count == 0) { return(false); } AGGSYM aggSym = ats.GetAggregate(); DebugUtil.Assert(aggSym != null); if (aggSym.TypeBuilder != null) { return(true); } TypeArray typeArgs = ats.AllTypeArguments; for (int i = 0; i < typeArgs.Count; ++i) { if (IsTypeBuilderInstruction(typeArgs[i])) { return(true); } } return(false); //---------------------------------------------------- // ARRAYSYM //---------------------------------------------------- case SYMKIND.ARRAYSYM: return(IsTypeBuilderInstruction(typeSym.ParentSym as TYPESYM)); //---------------------------------------------------- // VOIDSYM //---------------------------------------------------- case SYMKIND.VOIDSYM: return(false); //---------------------------------------------------- // PARAMMODSYM //---------------------------------------------------- case SYMKIND.PARAMMODSYM: return(IsTypeBuilderInstruction(typeSym.ParentSym as TYPESYM)); //---------------------------------------------------- // TYVARSYM //---------------------------------------------------- case SYMKIND.TYVARSYM: return(true); //---------------------------------------------------- // PTRSYM //---------------------------------------------------- case SYMKIND.PTRSYM: return(IsTypeBuilderInstruction((typeSym as PTRSYM).BaseTypeSym)); //---------------------------------------------------- // NUBSYM //---------------------------------------------------- case SYMKIND.NUBSYM: return(IsTypeBuilderInstruction((typeSym as NUBSYM).BaseTypeSym)); //---------------------------------------------------- // otherwise //---------------------------------------------------- case SYMKIND.NULLSYM: case SYMKIND.ERRORSYM: break; case SYMKIND.MODOPTTYPESYM: throw new NotImplementedException("SymbolUtil.MakeSystemType: MODOPTTYPESYM"); case SYMKIND.ANONMETHSYM: case SYMKIND.METHGRPSYM: case SYMKIND.UNITSYM: break; default: break; } return(false); }
//------------------------------------------------------------ // FUNCBREC.HasIEnumerable (2) // /// <summary> /// Rewrite HasIEnumerable for collection initializer. /// Return the IEnumerable or IEnumerable<T> instance. /// </summary> /// <param name="collection"></param> /// <param name="tree"></param> /// <param name="badType"></param> /// <param name="badMember"></param> /// <returns></returns> //------------------------------------------------------------ private AGGTYPESYM HasIEnumerable( TYPESYM collectionTypeSym/*, * BASENODE treeNode, * TYPESYM badTypeSym, * PREDEFNAME badMemberName*/ ) { AGGTYPESYM ifaceCandidateAts = null; // First try the generic interfaces AGGSYM gEnumAggSym = Compiler.GetOptPredefAgg(PREDEFTYPE.G_IENUMERABLE, true); TypeArray allIfacesTypeArray = null; AGGTYPESYM baseAts = null; // If generics don't exist or the type isn't an AGGTYPESYM // then we can't check the interfaces (and base-class interfaces) // for IEnumerable<T> so immediately try the non-generic IEnumerable if (gEnumAggSym == null) { goto NO_GENERIC; } if (collectionTypeSym.IsAGGTYPESYM) { if (collectionTypeSym.GetAggregate() == gEnumAggSym || collectionTypeSym.IsPredefType(PREDEFTYPE.IENUMERABLE)) { DebugUtil.Assert(false, "IEnumerable/ator types are bad!"); goto LERROR; } AGGTYPESYM tempAts = collectionTypeSym as AGGTYPESYM; allIfacesTypeArray = tempAts.GetIfacesAll(); baseAts = tempAts.GetBaseClass(); } else if (collectionTypeSym.IsTYVARSYM) { // Note: // we'll search the interface list before the class constraint, // but it doesn't matter since we require a unique instantiation of IEnumerable<T>. // Note: // The pattern search will usually find the interface constraint // - but if the class constraint has a non-public or non-applicable // or non-method GetEnumerator, // the interfaces are hidden in which case we will find them here. TYVARSYM tempTvSym = collectionTypeSym as TYVARSYM; allIfacesTypeArray = tempTvSym.AllInterfaces; baseAts = tempTvSym.BaseClassSym; } else { goto NO_GENERIC; } DebugUtil.Assert(allIfacesTypeArray != null); // If the type implements exactly one instantiation of // IEnumerable<T> then it's the one. // // If it implements none then try the non-generic interface. // // If it implements more than one, then it's an error. // // Search the direct and indirect interfaces via allIfacesTypeArray, // going up the base chain... // Work up the base chain for (; ;) { // Now work across all the interfaces for (int i = 0; i < allIfacesTypeArray.Count; ++i) { AGGTYPESYM iface = allIfacesTypeArray[i] as AGGTYPESYM; if (iface.GetAggregate() == gEnumAggSym) { if (ifaceCandidateAts == null) { // First implementation ifaceCandidateAts = iface; } else if (iface != ifaceCandidateAts) { // If this really is a different instantiation report an error Compiler.Error( treeNode, CSCERRID.ERR_MultipleIEnumOfT, new ErrArgRef(collectionTypeSym), new ErrArg(gEnumAggSym.GetThisType())); return(null); } } } // Check the base class. if (baseAts == null) { break; } allIfacesTypeArray = baseAts.GetIfacesAll(); baseAts = baseAts.GetBaseClass(); } // Report the one and only generic interface if (ifaceCandidateAts != null) { DebugUtil.Assert( CanConvert(collectionTypeSym, ifaceCandidateAts, ConvertTypeEnum.NOUDC)); return(ifaceCandidateAts); } NO_GENERIC: if (collectionTypeSym.IsPredefType(PREDEFTYPE.IENUMERABLE)) { DebugUtil.VsFail("Why didn't IEnumerator match the pattern?"); goto LERROR; } // No errors, no generic interfaces, try the non-generic interface ifaceCandidateAts = GetRequiredPredefinedType(PREDEFTYPE.IENUMERABLE); if (CanConvert(collectionTypeSym, ifaceCandidateAts, ConvertTypeEnum.NOUDC)) { return(ifaceCandidateAts); } LERROR: return(null); }
//------------------------------------------------------------ // MetaDataHelper.GetExplicitImplTypeName // /// <summary></summary> /// <param name="typeSym"></param> /// <param name="strBuilder"></param> //------------------------------------------------------------ public void GetExplicitImplTypeName(TYPESYM typeSym, StringBuilder strBuilder) { #if DEBUG if (!(typeSym != null)) { ; } #endif DebugUtil.Assert(typeSym != null); TYPESYM nakedTypeSym = typeSym.GetNakedType(false); TypeArray typeArgs = null; switch (nakedTypeSym.Kind) { default: DebugUtil.Assert(false, "Unhandled type in GetExplicitImplTypeName"); return; case SYMKIND.TYVARSYM: strBuilder.Append(nakedTypeSym.Name); break; case SYMKIND.NUBSYM: nakedTypeSym = (nakedTypeSym as NUBSYM).GetAggTypeSym(); if (nakedTypeSym == null) { DebugUtil.Assert(false, "Why did GetAts return null?"); return; } // Fall through. goto case SYMKIND.AGGTYPESYM; case SYMKIND.AGGTYPESYM: { AGGTYPESYM outerAggTypeSym = (nakedTypeSym as AGGTYPESYM).OuterTypeSym; AGGSYM aggSym = nakedTypeSym.GetAggregate(); if (outerAggTypeSym != null) { GetExplicitImplTypeName(outerAggTypeSym, strBuilder); strBuilder.Append('.'); } else { DebugUtil.Assert(aggSym.ParentBagSym != null && !aggSym.ParentBagSym.IsAGGSYM); int cch = strBuilder.Length; GetFullName(aggSym.ParentBagSym, strBuilder, aggSym); if (cch < strBuilder.Length) { strBuilder.Append('.'); } } strBuilder.Append(aggSym.Name); typeArgs = (nakedTypeSym as AGGTYPESYM).TypeArguments; } break; case SYMKIND.ERRORSYM: { ERRORSYM errSym = nakedTypeSym as ERRORSYM; SYM parentSym = errSym.ParentSym; if (parentSym != null && parentSym.IsTYPESYM) { GetExplicitImplTypeName(parentSym as TYPESYM, strBuilder); strBuilder.Append('.'); } else if (parentSym != null && parentSym.IsNSAIDSYM) { parentSym = (parentSym as NSAIDSYM).NamespaceSym; int cch = strBuilder.Length; GetFullName(parentSym, strBuilder, errSym); if (cch < strBuilder.Length) { strBuilder.Append('.'); } } strBuilder.Append(errSym.ErrorName); typeArgs = errSym.TypeArguments; } break; } if (typeArgs != null && typeArgs.Count > 0) { strBuilder.Append('<'); for (int i = 0; i < typeArgs.Count; ++i) { if (i > 0) { strBuilder.Append(','); } GetExplicitImplTypeName(typeArgs[i], strBuilder); } strBuilder.Append('>'); } // Add ptr and array modifiers AddTypeModifiers(typeSym, strBuilder); }
//------------------------------------------------------------ // FUNCBREC.BindImplicitlyTypedArrayInitConvert // /// <summary></summary> /// <param name="elementTypeSym"></param> /// <param name="dimList"></param> /// <param name="dimIndex"></param> /// <param name="argListExpr"></param> /// <param name="nonConstCount"></param> /// <param name="constCount"></param> /// <param name="hasSideEffects"></param> //------------------------------------------------------------ internal void BindImplicitlyTypedArrayInitConvert( TYPESYM elementTypeSym, List <int> dimList, int dimIndex, ref EXPR argListExpr, ref int nonConstCount, ref int constCount, ref bool hasSideEffects) { int count = 0; EXPR nodeExpr = argListExpr; EXPR topArgList = null, lastArgList = null; while (nodeExpr != null) { EXPR argExpr; if (nodeExpr.Kind == EXPRKIND.LIST) { EXPRBINOP listExpr = nodeExpr as EXPRBINOP; argExpr = listExpr.Operand1; nodeExpr = listExpr.Operand2; } else { argExpr = nodeExpr; nodeExpr = null; } count++; EXPR expr = null; #if false expr = MustConvert( argExpr, elementTypeSym, 0); #endif if (!BindImplicitConversion( argExpr.TreeNode, argExpr, argExpr.TypeSym, elementTypeSym, ref expr, 0)) { Compiler.Error(argExpr.TreeNode, CSCERRID.ERR_NoBestTypeForArray); expr = NewError(treeNode, elementTypeSym); } EXPR constExpr = expr.GetConst(); if (constExpr != null) { if (!constExpr.IsZero(true)) { ++constCount; } if (expr.HasSideEffects(Compiler)) { hasSideEffects = true; } } else { nonConstCount++; } NewList(expr, ref topArgList, ref lastArgList); //exprList.Add(expr); } argListExpr = topArgList; }