///////////////////////////////////////////////////////////////////////////////// // Expression types. private ExprBinOp VisitBoundLambda(ExprBoundLambda anonmeth) { Debug.Assert(anonmeth != null); MethodSymbol lambdaMethod = GetPreDefMethod(PREDEFMETH.PM_EXPRESSION_LAMBDA); AggregateType delegateType = anonmeth.DelegateType; TypeArray lambdaTypeParams = TypeArray.Allocate(delegateType); AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION); MethWithInst mwi = new MethWithInst(lambdaMethod, expressionType, lambdaTypeParams); Expr createParameters = CreateWraps(anonmeth); Debug.Assert(createParameters != null); Debug.Assert(anonmeth.Expression != null); Expr body = Visit(anonmeth.Expression); Debug.Assert(anonmeth.ArgumentScope.nextChild == null); Expr parameters = GenerateParamsArray(null, PredefinedType.PT_PARAMETEREXPRESSION); Expr args = ExprFactory.CreateList(body, parameters); CType typeRet = TypeManager.SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi); ExprCall call = ExprFactory.CreateCall(0, typeRet, args, pMemGroup, mwi); call.PredefinedMethod = PREDEFMETH.PM_EXPRESSION_LAMBDA; return(ExprFactory.CreateSequence(createParameters, call)); }
static public BindingContext CreateInstance( CSemanticChecker pSemanticChecker, ExprFactory exprFactory, OutputContext outputContext, NameGenerator nameGenerator, bool bflushLocalVariableTypesForEachStatement, bool bAllowUnsafeBlocks, bool bIsOptimizingSwitchAndArrayInit, bool bShowReachability, bool bWrapNonExceptionThrows, bool bInRefactoring, KAID aidLookupContext ) { return new BindingContext( pSemanticChecker, exprFactory, outputContext, nameGenerator, bflushLocalVariableTypesForEachStatement, bAllowUnsafeBlocks, bIsOptimizingSwitchAndArrayInit, bShowReachability, bWrapNonExceptionThrows, bInRefactoring, aidLookupContext); }
private static Expr CreateWraps(ExprBoundLambda anonmeth) { Expr sequence = null; for (Symbol sym = anonmeth.ArgumentScope.firstChild; sym != null; sym = sym.nextChild) { if (!(sym is LocalVariableSymbol local)) { continue; } Debug.Assert(anonmeth.Expression != null); Expr create = GenerateParameter(local.name.Text, local.GetType()); local.wrap = ExprFactory.CreateWrap(create); Expr save = ExprFactory.CreateSave(local.wrap); if (sequence == null) { sequence = save; } else { sequence = ExprFactory.CreateSequence(sequence, save); } } return(sequence); }
static public BindingContext CreateInstance( CSemanticChecker pSemanticChecker, ExprFactory exprFactory, OutputContext outputContext, NameGenerator nameGenerator, bool bflushLocalVariableTypesForEachStatement, bool bAllowUnsafeBlocks, bool bIsOptimizingSwitchAndArrayInit, bool bShowReachability, bool bWrapNonExceptionThrows, bool bInRefactoring, KAID aidLookupContext ) { return(new BindingContext( pSemanticChecker, exprFactory, outputContext, nameGenerator, bflushLocalVariableTypesForEachStatement, bAllowUnsafeBlocks, bIsOptimizingSwitchAndArrayInit, bShowReachability, bWrapNonExceptionThrows, bInRefactoring, aidLookupContext)); }
public BindingContext(CSemanticChecker semanticChecker, ExprFactory exprFactory) { Debug.Assert(semanticChecker != null); ExprFactory = exprFactory; SemanticChecker = semanticChecker; SymbolLoader = semanticChecker.SymbolLoader; }
protected BindingContext( CSemanticChecker pSemanticChecker, ExprFactory exprFactory, OutputContext outputContext, NameGenerator nameGenerator, bool bflushLocalVariableTypesForEachStatement, bool bAllowUnsafeBlocks, bool bIsOptimizingSwitchAndArrayInit, bool bShowReachability, bool bWrapNonExceptionThrows, bool bInRefactoring, KAID aidLookupContext ) { m_ExprFactory = exprFactory; m_outputContext = outputContext; m_pNameGenerator = nameGenerator; m_pInputFile = null; m_pParentDecl = null; m_pContainingAgg = null; m_pCurrentSwitchType = null; m_pOriginalConstantField = null; m_pCurrentFieldSymbol = null; m_pImplicitlyTypedLocal = null; m_pOuterScope = null; m_pFinallyScope = null; m_pTryScope = null; m_pCatchScope = null; m_pCurrentScope = null; m_pSwitchScope = null; m_pCurrentBlock = null; m_UnsafeState = UNSAFESTATES.UNSAFESTATES_Unknown; m_FinallyNestingCount = 0; m_bInsideTryOfCatch = false; m_bInFieldInitializer = false; m_bInBaseConstructorCall = false; m_bAllowUnsafeBlocks = bAllowUnsafeBlocks; m_bIsOptimizingSwitchAndArrayInit = bIsOptimizingSwitchAndArrayInit; m_bShowReachability = bShowReachability; m_bWrapNonExceptionThrows = bWrapNonExceptionThrows; m_bInRefactoring = bInRefactoring; m_bInAttribute = false; m_bRespectSemanticsAndReportErrors = true; m_bflushLocalVariableTypesForEachStatement = bflushLocalVariableTypesForEachStatement; m_ppamis = null; m_pamiCurrent = null; m_pInitType = null; m_returnErrorSink = null; Debug.Assert(pSemanticChecker != null); this.SemanticChecker = pSemanticChecker; this.SymbolLoader = SemanticChecker.GetSymbolLoader(); m_outputContext.m_pThisPointer = null; m_outputContext.m_pCurrentMethodSymbol = null; m_aidExternAliasLookupContext = aidLookupContext; CheckedNormal = false; CheckedConstant = false; }
private static Expr GenerateParameter(string name, CType CType) { SymbolLoader.GetPredefindType(PredefinedType.PT_STRING); // force an ensure state ExprConstant nameString = ExprFactory.CreateStringConstant(name); ExprTypeOf pTypeOf = CreateTypeOf(CType); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_PARAMETER, pTypeOf, nameString)); }
private static ExprArrayInit GenerateParamsArray(Expr args, PredefinedType pt) { int parameterCount = ExpressionIterator.Count(args); AggregateType paramsArrayElementType = SymbolLoader.GetPredefindType(pt); ArrayType paramsArrayType = TypeManager.GetArray(paramsArrayElementType, 1, true); ExprConstant paramsArrayArg = ExprFactory.CreateIntegerConstant(parameterCount); return(ExprFactory.CreateArrayInit(paramsArrayType, args, paramsArrayArg, new int[] { parameterCount })); }
private Expr GenerateConstructor(ExprCall expr) { Debug.Assert(expr != null); Debug.Assert(expr.MethWithInst.Meth().IsConstructor()); Expr constructorInfo = ExprFactory.CreateMethodInfo(expr.MethWithInst); Expr args = GenerateArgsList(expr.OptionalArguments); Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_NEW, constructorInfo, Params)); }
private Expr GenerateUserDefinedUnaryOperator(ExprUnaryOp expr) { Debug.Assert(expr != null); PREDEFMETH pdm; Expr arg = expr.Child; ExprCall call = (ExprCall)expr.OptionalUserDefinedCall; if (call != null) { // Use the actual argument of the call; it may contain user-defined // conversions or be a bound lambda, and that will not be in the original // argument stashed away in the left child of the operator. arg = call.OptionalArguments; } Debug.Assert(arg != null && arg.Kind != ExpressionKind.List); switch (expr.Kind) { case ExpressionKind.True: case ExpressionKind.False: return(Visit(call)); case ExpressionKind.UnaryPlus: pdm = PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED; break; case ExpressionKind.BitwiseNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED; break; case ExpressionKind.LogicalNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED; break; case ExpressionKind.DecimalNegate: case ExpressionKind.Negate: pdm = expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED; break; case ExpressionKind.Inc: case ExpressionKind.Dec: case ExpressionKind.DecimalInc: case ExpressionKind.DecimalDec: pdm = PREDEFMETH.PM_EXPRESSION_CALL; break; default: throw Error.InternalCompilerError(); } Expr op = Visit(arg); Expr methodInfo = ExprFactory.CreateMethodInfo(expr.UserDefinedCallMethod); if (expr.Kind == ExpressionKind.Inc || expr.Kind == ExpressionKind.Dec || expr.Kind == ExpressionKind.DecimalInc || expr.Kind == ExpressionKind.DecimalDec) { return(GenerateCall(pdm, null, methodInfo, GenerateParamsArray(op, PredefinedType.PT_EXPRESSION))); } return(GenerateCall(pdm, op, methodInfo)); }
// Create an expr for new T?(exprSrc) where T is exprSrc.type. private static ExprCall BindNubNew(Expr exprSrc) { Debug.Assert(exprSrc != null); NullableType pNubSourceType = TypeManager.GetNullable(exprSrc.Type); AggregateType pSourceType = pNubSourceType.GetAts(); MethodSymbol meth = PredefinedMembers.GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); MethWithInst methwithinst = new MethWithInst(meth, pSourceType, TypeArray.Empty); ExprMemberGroup memgroup = ExprFactory.CreateMemGroup(null, methwithinst); return(ExprFactory.CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, exprSrc, memgroup, methwithinst)); }
private Expr GenerateArgsList(Expr oldArgs) { Expr newArgs = null; Expr newArgsTail = newArgs; for (ExpressionIterator it = new ExpressionIterator(oldArgs); !it.AtEnd(); it.MoveNext()) { Expr oldArg = it.Current(); ExprFactory.AppendItemToList(Visit(oldArg), ref newArgs, ref newArgsTail); } return(newArgs); }
private Expr GenerateUserDefinedComparisonOperator(ExprBinOp expr) { Debug.Assert(expr != null); PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.StringEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.StringNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.DelegateEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.DelegateNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.Eq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.NotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.LessThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED; break; case ExpressionKind.LessThan: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED; break; case ExpressionKind.GreaterThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED; break; case ExpressionKind.GreaterThan: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED; break; default: throw Error.InternalCompilerError(); } Expr p1 = expr.OptionalLeftChild; Expr p2 = expr.OptionalRightChild; if (expr.OptionalUserDefinedCall != null) { ExprCall udcall = (ExprCall)expr.OptionalUserDefinedCall; ExprList args = (ExprList)udcall.OptionalArguments; Debug.Assert(args.OptionalNextListNode.Kind != ExpressionKind.List); p1 = args.OptionalElement; p2 = args.OptionalNextListNode; } p1 = Visit(p1); p2 = Visit(p2); FixLiftedUserDefinedBinaryOperators(expr, ref p1, ref p2); Expr lift = ExprFactory.CreateBoolConstant(false); // We never lift to null in C#. Expr methodInfo = ExprFactory.CreateMethodInfo(expr.UserDefinedCallMethod); return(GenerateCall(pdm, p1, p2, lift, methodInfo)); }
protected override Expr VisitFIELD(ExprField expr) { Debug.Assert(expr != null); Expr pObject; if (expr.OptionalObject == null) { pObject = ExprFactory.CreateNull(); } else { pObject = Visit(expr.OptionalObject); } ExprFieldInfo pFieldInfo = ExprFactory.CreateFieldInfo(expr.FieldWithType.Field(), expr.FieldWithType.GetType()); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_FIELD, pObject, pFieldInfo)); }
private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3, Expr arg4) { MethodSymbol method = GetPreDefMethod(pdm); if (method == null) { return(null); } AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION); Expr args = ExprFactory.CreateList(arg1, arg2, arg3, arg4); MethWithInst mwi = new MethWithInst(method, expressionType); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi); ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi); call.PredefinedMethod = pdm; return(call); }
public static EXPR Map(this EXPR expr, ExprFactory factory, Func<EXPR, EXPR> f) { Debug.Assert(f != null); Debug.Assert(factory != null); if (expr == null) return f(expr); EXPR result = null; EXPR tail = null; foreach (EXPR item in expr.ToEnumerable()) { EXPR mappedItem = f(item); factory.AppendItemToList(mappedItem, ref result, ref tail); } return result; }
private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1) { MethodSymbol method = GetPreDefMethod(pdm); // this should be enforced in an earlier pass and the transform pass should not // be handling this error if (method == null) { return(null); } AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION); MethWithInst mwi = new MethWithInst(method, expressionType); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi); ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi); call.PredefinedMethod = pdm; return(call); }
private bool bindImplicitConversionToEnum(AggregateType aggTypeSrc) { // The spec states: // ***************** // 13.1.3 Implicit enumeration conversions // // An implicit enumeration conversion permits the decimal-integer-literal 0 to be converted to any // enum-type. // ***************** // However, we actually allow any constant zero, not just the integer literal zero, to be converted // to enum. The reason for this is for backwards compatibility with a premature optimization // that used to be in the binding layer. We would optimize away expressions such as 0 | blah to be // just 0, but not erase the "is literal" bit. This meant that expression such as 0 | 0 | E.X // would succeed rather than correctly producing an error pointing out that 0 | 0 is not a literal // zero and therefore does not convert to any enum. // // We have removed the premature optimization but want old code to continue to compile. Rather than // try to emulate the somewhat complex behaviour of the previous optimizer, it is easier to simply // say that any compile time constant zero is convertible to any enum. This means unfortunately // expressions such as (7-7) * 12 are convertible to enum, but frankly, that's better than having // some terribly complex rule about what constitutes a legal zero and what doesn't. // Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants. if ( aggTypeSrc.OwningAggregate.GetPredefType() != PredefinedType.PT_BOOL && _exprSrc != null && _exprSrc.IsZero() && _exprSrc.Type.IsNumericType && /*(exprSrc.flags & EXF_LITERALCONST) &&*/ 0 == (_flags & CONVERTTYPE.STANDARD)) { // NOTE: This allows conversions from uint, long, ulong, float, double, and hexadecimal int // NOTE: This is for backwards compatibility with Everett // This is another place where we lose Expr fidelity. We shouldn't fold this // into a constant here - we should move this to a later pass. if (_needsExprDest) { _exprDest = ExprFactory.CreateConstant(_typeDest, ConstVal.GetDefaultValue(_typeDest.ConstValKind)); } return(true); } return(false); }
public static Expr Map(this Expr expr, Func <Expr, Expr> f) { Debug.Assert(f != null); if (expr == null) { return(f(null)); } Expr result = null; Expr tail = null; foreach (Expr item in expr.ToEnumerable()) { Expr mappedItem = f(item); ExprFactory.AppendItemToList(mappedItem, ref result, ref tail); } return(result); }
private static Expr GenerateUserDefinedConversion(Expr arg, CType CType, Expr target, MethWithInst method) { // The user-defined explicit conversion from enum? to decimal or decimal? requires // that we convert the enum? to its nullable underlying CType. if (isEnumToDecimalConversion(arg.Type, CType)) { // Special case: If we have enum? to decimal? then we need to emit // a conversion from enum? to its nullable underlying CType first. // This is unfortunate; we ought to reorganize how conversions are // represented in the Expr tree so that this is more transparent. // converting an enum to its underlying CType never fails, so no need to check it. CType underlyingType = arg.Type.StripNubs().UnderlyingEnumType; CType nullableType = TypeManager.GetNullable(underlyingType); Expr typeofNubEnum = CreateTypeOf(nullableType); target = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, target, typeofNubEnum); } // If the methodinfo does not return the target CType AND this is not a lifted conversion // from one value CType to another, then we need to wrap the whole thing in another conversion, // e.g. if we have a user-defined conversion from int to S? and we have (S)myint, then we need to generate // Convert(Convert(myint, typeof(S?), op_implicit), typeof(S)) CType pMethodReturnType = TypeManager.SubstType(method.Meth().RetType, method.GetType(), method.TypeArgs); bool fDontLiftReturnType = (pMethodReturnType == CType || (IsNullableValueType(arg.Type) && IsNullableValueType(CType))); Expr typeofInner = CreateTypeOf(fDontLiftReturnType ? CType : pMethodReturnType); Expr methodInfo = ExprFactory.CreateMethodInfo(method); PREDEFMETH pdmInner = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED; Expr callUserDefinedConversion = GenerateCall(pdmInner, target, typeofInner, methodInfo); if (fDontLiftReturnType) { return(callUserDefinedConversion); } PREDEFMETH pdmOuter = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT; Expr typeofOuter = CreateTypeOf(CType); return(GenerateCall(pdmOuter, callUserDefinedConversion, typeofOuter)); }
public static EXPR Map(this EXPR expr, ExprFactory factory, Func <EXPR, EXPR> f) { Debug.Assert(f != null); Debug.Assert(factory != null); if (expr == null) { return(f(expr)); } EXPR result = null; EXPR tail = null; foreach (EXPR item in expr.ToEnumerable()) { EXPR mappedItem = f(item); factory.AppendItemToList(mappedItem, ref result, ref tail); } return(result); }
private Expr GenerateIndexList(Expr oldIndices) { CType intType = SymbolLoader.GetPredefindType(PredefinedType.PT_INT); Expr newIndices = null; Expr newIndicesTail = newIndices; for (ExpressionIterator it = new ExpressionIterator(oldIndices); !it.AtEnd(); it.MoveNext()) { Expr newIndex = it.Current(); if (newIndex.Type != intType) { newIndex = ExprFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, intType, newIndex); newIndex.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } Expr rewrittenIndex = Visit(newIndex); ExprFactory.AppendItemToList(rewrittenIndex, ref newIndices, ref newIndicesTail); } return(newIndices); }
protected override Expr VisitCONCAT(ExprConcat expr) { Debug.Assert(expr != null); PREDEFMETH pdm; if (expr.FirstArgument.Type.IsPredefType(PredefinedType.PT_STRING) && expr.SecondArgument.Type.IsPredefType(PredefinedType.PT_STRING)) { pdm = PREDEFMETH.PM_STRING_CONCAT_STRING_2; } else { pdm = PREDEFMETH.PM_STRING_CONCAT_OBJECT_2; } Expr p1 = Visit(expr.FirstArgument); Expr p2 = Visit(expr.SecondArgument); MethodSymbol method = GetPreDefMethod(pdm); Expr methodInfo = ExprFactory.CreateMethodInfo(method, SymbolLoader.GetPredefindType(PredefinedType.PT_STRING), null); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED, p1, p2, methodInfo)); }
// Create an expr for exprSrc.Value where exprSrc.type is a NullableType. private static Expr BindNubValue(Expr exprSrc) { Debug.Assert(exprSrc != null && exprSrc.Type is NullableType); // For new T?(x), the answer is x. if (IsNullableConstructor(exprSrc, out ExprCall call)) { Expr args = call.OptionalArguments; Debug.Assert(args != null && !(args is ExprList)); return(args); } NullableType nubSrc = (NullableType)exprSrc.Type; CType typeBase = nubSrc.UnderlyingType; AggregateType ats = nubSrc.GetAts(); PropertySymbol prop = PredefinedMembers.GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE); PropWithType pwt = new PropWithType(prop, ats); MethPropWithInst mpwi = new MethPropWithInst(prop, ats); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(exprSrc, mpwi); return(ExprFactory.CreateProperty(typeBase, null, null, pMemGroup, pwt, null)); }
///////////////////////////////////////////////////////////////////////////////// // Statement types. protected override Expr VisitASSIGNMENT(ExprAssignment assignment) { Debug.Assert(assignment != null); // For assignments, we either have a member assignment or an indexed assignment. //Debug.Assert(assignment.GetLHS().isPROP() || assignment.GetLHS().isFIELD() || assignment.GetLHS().isARRAYINDEX() || assignment.GetLHS().isLOCAL()); Expr lhs; if (assignment.LHS is ExprProperty prop) { if (prop.OptionalArguments == null) { // Regular property. lhs = Visit(prop); } else { // Indexed assignment. Here we need to find the instance of the object, create the // PropInfo for the thing, and get the array of expressions that make up the index arguments. // // The LHS becomes Expression.Property(instance, indexerInfo, arguments). Expr instance = Visit(prop.MemberGroup.OptionalObject); Expr propInfo = ExprFactory.CreatePropertyInfo(prop.PropWithTypeSlot.Prop(), prop.PropWithTypeSlot.Ats); Expr arguments = GenerateParamsArray( GenerateArgsList(prop.OptionalArguments), PredefinedType.PT_EXPRESSION); lhs = GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, instance, propInfo, arguments); } } else { lhs = Visit(assignment.LHS); } Expr rhs = Visit(assignment.RHS); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_ASSIGN, lhs, rhs)); }
private bool bindImplicitConversionFromNull() { // null type can be implicitly converted to any reference type or pointer type or type // variable with reference-type constraint. FUNDTYPE ftDest = _typeDest.FundamentalType; if (ftDest != FUNDTYPE.FT_REF && ftDest != FUNDTYPE.FT_PTR && // null is convertible to System.Nullable<T>. !_typeDest.IsPredefType(PredefinedType.PT_G_OPTIONAL)) { return false; } if (_needsExprDest) { // If the conversion argument is a constant null then return a ZEROINIT. // Otherwise, bind this as a cast to the destination type. In a later // rewrite pass we will rewrite the cast as SEQ(side effects, ZEROINIT). _exprDest = _exprSrc is ExprConstant ? ExprFactory.CreateZeroInit(_typeDest) : ExprFactory.CreateCast(_typeDest, _exprSrc); } return true; }
protected override Expr VisitPROP(ExprProperty expr) { Debug.Assert(expr != null); Expr pObject; if (expr.PropWithTypeSlot.Prop().isStatic || expr.MemberGroup.OptionalObject == null) { pObject = ExprFactory.CreateNull(); } else { pObject = Visit(expr.MemberGroup.OptionalObject); } Expr propInfo = ExprFactory.CreatePropertyInfo(expr.PropWithTypeSlot.Prop(), expr.PropWithTypeSlot.GetType()); if (expr.OptionalArguments != null) { // It is an indexer property. Turn it into a virtual method call. Expr args = GenerateArgsList(expr.OptionalArguments); Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, pObject, propInfo, Params)); } return(GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, pObject, propInfo)); }
private static Expr GenerateConstant(Expr expr) { EXPRFLAG flags = 0; AggregateType pObject = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT); if (expr.Type is NullType) { ExprTypeOf pTypeOf = CreateTypeOf(pObject); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, expr, pTypeOf)); } AggregateType stringType = SymbolLoader.GetPredefindType(PredefinedType.PT_STRING); if (expr.Type != stringType) { flags = EXPRFLAG.EXF_BOX; } ExprCast cast = ExprFactory.CreateCast(flags, pObject, expr); ExprTypeOf pTypeOf2 = CreateTypeOf(expr.Type); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, cast, pTypeOf2)); }
protected ExpressionTreeRewriter(ExprFactory expressionFactory, SymbolLoader symbolLoader) { this.expressionFactory = expressionFactory; this.symbolLoader = symbolLoader; this.alwaysRewrite = false; }
public static EXPR Rewrite(EXPR expr, ExprFactory expressionFactory, SymbolLoader symbolLoader) { ExpressionTreeRewriter rewriter = new ExpressionTreeRewriter(expressionFactory, symbolLoader); rewriter.alwaysRewrite = true; return rewriter.Visit(expr); }
private ExpressionTreeRewriter(ExprFactory expressionFactory, SymbolLoader symbolLoader) { this.expressionFactory = expressionFactory; this.symbolLoader = symbolLoader; }
public static ExprBinOp Rewrite(ExprBoundLambda expr, ExprFactory expressionFactory, SymbolLoader symbolLoader) => new ExpressionTreeRewriter(expressionFactory, symbolLoader).VisitBoundLambda(expr);
public CNullable(SymbolLoader symbolLoader, ErrorHandling errorContext, ExprFactory exprFactory) { _pSymbolLoader = symbolLoader; _pErrorContext = errorContext; _exprFactory = exprFactory; }
private void Reset() { _controller = new RuntimeBinderController(); _semanticChecker = new LangCompiler(_controller, new NameManager()); BSYMMGR bsymmgr = _semanticChecker.getBSymmgr(); NameManager nameManager = _semanticChecker.GetNameManager(); InputFile infile = bsymmgr.GetMiscSymFactory().CreateMDInfile(nameManager.Lookup(""), (mdToken)0); infile.SetAssemblyID(bsymmgr.AidAlloc(infile)); infile.AddToAlias(KAID.kaidThisAssembly); infile.AddToAlias(KAID.kaidGlobal); _symbolTable = new SymbolTable( bsymmgr.GetSymbolTable(), bsymmgr.GetSymFactory(), nameManager, _semanticChecker.GetTypeManager(), bsymmgr, _semanticChecker, infile); _semanticChecker.getPredefTypes().Init(_semanticChecker.GetErrorContext(), _symbolTable); _semanticChecker.GetTypeManager().InitTypeFactory(_symbolTable); SymbolLoader.getPredefinedMembers().RuntimeBinderSymbolTable = _symbolTable; SymbolLoader.SetSymbolTable(_symbolTable); _exprFactory = new ExprFactory(_semanticChecker.GetSymbolLoader().GetGlobalSymbolContext()); _outputContext = new OutputContext(); _nameGenerator = new NameGenerator(); _bindingContext = BindingContext.CreateInstance( _semanticChecker, _exprFactory, _outputContext, _nameGenerator, false, true, false, false, false, false, 0); _binder = new ExpressionBinder(_bindingContext); }
/*************************************************************************************************** * 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. ***************************************************************************************************/ private bool BindNubConversion(NullableType nubDst) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! Debug.Assert(0 != (~_flags & (CONVERTTYPE.STANDARD | CONVERTTYPE.ISEXPLICIT))); Debug.Assert(_exprSrc == null || _exprSrc.Type == _typeSrc); Debug.Assert(!_needsExprDest || _exprSrc != null); Debug.Assert(_typeSrc != nubDst); // BindImplicitConversion should have taken care of this already. AggregateType atsDst = nubDst.GetAts(); // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (SymbolLoader.HasBaseConversion(nubDst.UnderlyingType, _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst)) { // These should be different! Fix the caller if typeSrc is an AggregateType of Nullable. Debug.Assert(atsDst != _typeSrc); // typeSrc is a base type of the destination nullable type so there is an explicit // unboxing conversion. if (0 == (_flags & CONVERTTYPE.ISEXPLICIT)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } bool dstWasNullable; bool srcWasNullable; CType typeDstBase = nubDst.StripNubs(out dstWasNullable); CType typeSrcBase = _typeSrc.StripNubs(out srcWasNullable); ConversionFunc pfn = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)_binder.BindExplicitConversion : (ConversionFunc)_binder.BindImplicitConversion; if (!srcWasNullable) { Debug.Assert(_typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (_typeSrc is NullType) { // If we have the constant null, generate it as a default value of T?. If we have // some wacky expression which has been determined to be always null, like (null??null) // keep it in its expression form and transform it in the nullable rewrite pass. if (_needsExprDest) { _exprDest = _exprSrc is ExprConstant ? ExprFactory.CreateZeroInit(nubDst) : ExprFactory.CreateCast(_typeDest, _exprSrc); } return(true); } Expr exprTmp = _exprSrc; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (_typeSrc == typeDstBase || pfn(_exprSrc, _typeSrc, typeDstBase, _needsExprDest, out exprTmp, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { ExprUserDefinedConversion exprUDC = exprTmp as ExprUserDefinedConversion; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } if (dstWasNullable) { ExprCall call = BindNubNew(exprTmp); exprTmp = call; call.NullableCallLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprTmp = exprUDC; } Debug.Assert(exprTmp.Type == nubDst); _exprDest = exprTmp; } return(true); } // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } // 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 (typeSrcBase != typeDstBase && !pfn(null, typeSrcBase, typeDstBase, false, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } if (_needsExprDest) { MethWithInst mwi = new MethWithInst(null, null); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi); ExprCall exprDst = ExprFactory.CreateCall(0, nubDst, _exprSrc, pMemGroup, null); // Here we want to first check whether or not the conversions work on the base types. Expr arg1 = _binder.mustCast(_exprSrc, typeSrcBase); bool convertible = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? _binder.BindExplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC) : _binder.BindImplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC); if (!convertible) { Debug.Fail("bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } exprDst.CastOfNonLiftedResultToLiftedType = _binder.mustCast(arg1, nubDst, 0); exprDst.NullableCallLiftKind = NullableCallLiftKind.NullableConversion; exprDst.PConversions = exprDst.CastOfNonLiftedResultToLiftedType; _exprDest = exprDst; } return(true); }
///////////////////////////////////////////////////////////////////////////////// private static EXPR GenerateOptionalArgument( SymbolLoader symbolLoader, ExprFactory exprFactory, MethodOrPropertySymbol methprop, CType type, int index) { CType pParamType = type; CType pRawParamType = type.IsNullableType() ? type.AsNullableType().GetUnderlyingType() : type; EXPR optionalArgument = null; if (methprop.HasDefaultParameterValue(index)) { CType pConstValType = methprop.GetDefaultParameterValueConstValType(index); CONSTVAL cv = methprop.GetDefaultParameterValue(index); if (pConstValType.isPredefType(PredefinedType.PT_DATETIME) && (pRawParamType.isPredefType(PredefinedType.PT_DATETIME) || pRawParamType.isPredefType(PredefinedType.PT_OBJECT) || pRawParamType.isPredefType(PredefinedType.PT_VALUE))) { // This is the specific case where we want to create a DateTime // but the constval that stores it is a long. AggregateType dateTimeType = symbolLoader.GetReqPredefType(PredefinedType.PT_DATETIME); optionalArgument = exprFactory.CreateConstant(dateTimeType, new CONSTVAL(DateTime.FromBinary(cv.longVal))); } else if (pConstValType.isSimpleOrEnumOrString()) { // In this case, the constval is a simple type (all the numerics, including // decimal), or an enum or a string. This covers all the substantial values, // and everything else that can be encoded is just null or default(something). // For enum parameters, we create a constant of the enum type. For everything // else, we create the appropriate constant. if (pRawParamType.isEnumType() && pConstValType == pRawParamType.underlyingType()) { optionalArgument = exprFactory.CreateConstant(pRawParamType, cv); } else { optionalArgument = exprFactory.CreateConstant(pConstValType, cv); } } else if ((pParamType.IsRefType() || pParamType.IsNullableType()) && cv.IsNullRef()) { // We have an "= null" default value with a reference type or a nullable type. optionalArgument = exprFactory.CreateNull(); } else { // We have a default value that is encoded as a nullref, and that nullref is // interpreted as default(something). For instance, the pParamType could be // a type parameter type or a non-simple value type. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } else { // There was no default parameter specified, so generally use default(T), // except for some cases when the parameter type in metatdata is object. if (pParamType.isPredefType(PredefinedType.PT_OBJECT)) { if (methprop.MarshalAsObject(index)) { // For [opt] parameters of type object, if we have marshal(iunknown), // marshal(idispatch), or marshal(interface), then we emit a null. optionalArgument = exprFactory.CreateNull(); } else { // Otherwise, we generate Type.Missing AggregateSymbol agg = symbolLoader.GetOptPredefAgg(PredefinedType.PT_MISSING); Name name = symbolLoader.GetNameManager().GetPredefinedName(PredefinedName.PN_CAP_VALUE); FieldSymbol field = symbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol).AsFieldSymbol(); FieldWithType fwt = new FieldWithType(field, agg.getThisType()); EXPRFIELD exprField = exprFactory.CreateField(0, agg.getThisType(), null, 0, fwt, null); if (agg.getThisType() != type) { optionalArgument = exprFactory.CreateCast(0, type, exprField); } else { optionalArgument = exprField; } } } else { // Every type aside from object that doesn't have a default value gets // its default value. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } Debug.Assert(optionalArgument != null); optionalArgument.IsOptionalArgument = true; return optionalArgument; }
internal static bool ReOrderArgsForNamedArguments( MethodOrPropertySymbol methprop, TypeArray pCurrentParameters, AggregateType pCurrentType, EXPRMEMGRP pGroup, ArgInfos pArguments, TypeManager typeManager, ExprFactory exprFactory, SymbolLoader symbolLoader) { // We use the param count from pCurrentParameters because they may have been resized // for param arrays. int numParameters = pCurrentParameters.size; EXPR[] pExprArguments = new EXPR[numParameters]; // Now go through the parameters. First set all positional arguments in the new argument // set, then for the remainder, look for a named argument with a matching name. int index = 0; EXPR paramArrayArgument = null; TypeArray @params = typeManager.SubstTypeArray( pCurrentParameters, pCurrentType, pGroup.typeArgs); foreach (Name name in methprop.ParameterNames) { // This can happen if we had expanded our param array to size 0. if (index >= pCurrentParameters.size) { break; } // If: // (1) we have a param array method // (2) we're on the last arg // (3) the thing we have is an array init thats generated for param array // then let us through. if (methprop.isParamArray && index < pArguments.carg && pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray) { paramArrayArgument = pArguments.prgexpr[index]; } // Positional. if (index < pArguments.carg && !pArguments.prgexpr[index].isNamedArgumentSpecification() && !(pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray)) { pExprArguments[index] = pArguments.prgexpr[index++]; continue; } // Look for names. EXPR pNewArg = FindArgumentWithName(pArguments, name); if (pNewArg == null) { if (methprop.IsParameterOptional(index)) { pNewArg = GenerateOptionalArgument(symbolLoader, exprFactory, methprop, @params.Item(index), index); } else if (paramArrayArgument != null && index == methprop.Params.Count - 1) { // If we have a param array argument and we're on the last one, then use it. pNewArg = paramArrayArgument; } else { // No name and no default value. return false; } } pExprArguments[index++] = pNewArg; } // Here we've found all the arguments, or have default values for them. CType[] prgTypes = new CType[pCurrentParameters.size]; for (int i = 0; i < numParameters; i++) { if (i < pArguments.prgexpr.Count) { pArguments.prgexpr[i] = pExprArguments[i]; } else { pArguments.prgexpr.Add(pExprArguments[i]); } prgTypes[i] = pArguments.prgexpr[i].type; } pArguments.carg = pCurrentParameters.size; pArguments.types = symbolLoader.getBSymmgr().AllocParams(pCurrentParameters.size, prgTypes); return true; }