public static EXPR StripNullableConstructor(EXPR pExpr) { while (IsNullableConstructor(pExpr)) { Debug.Assert(pExpr.isCALL()); pExpr = pExpr.asCALL().GetOptionalArguments(); Debug.Assert(pExpr != null && !pExpr.isLIST()); } return pExpr; }
protected override EXPR Dispatch(EXPR expr) { Debug.Assert(expr != null); EXPR result = base.Dispatch(expr); if (result == expr) { throw Error.InternalCompilerError(); } return result; }
public ImplicitConversion(ExpressionBinder binder, EXPR exprSrc, CType typeSrc, EXPRTYPEORNAMESPACE typeDest, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest.TypeOrNamespace.AsType(); _exprTypeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; }
// ---------------------------------------------------------------------------- // BindExplicitConversion // ---------------------------------------------------------------------------- public ExplicitConversion(ExpressionBinder binder, EXPR exprSrc, CType typeSrc, EXPRTYPEORNAMESPACE typeDest, CType pDestinationTypeForLambdaErrorReporting, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest.TypeOrNamespace.AsType(); _pDestinationTypeForLambdaErrorReporting = pDestinationTypeForLambdaErrorReporting; _exprTypeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; }
public EXPRFUNCPTR CreateFunctionPointer(EXPRFLAG nFlags, CType pType, EXPR pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); EXPRFUNCPTR rval = new EXPRFUNCPTR(); rval.kind = ExpressionKind.EK_FUNCPTR; rval.type = pType; rval.flags = nFlags; rval.OptionalObject = pObject; rval.mwi = new MethWithInst(MWI); Debug.Assert(rval != null); return (rval); }
public EXPRFIELD CreateField(EXPRFLAG nFlags, CType pType, EXPR pOptionalObject, uint nOffset, FieldWithType FWT, EXPR pOptionalLHS) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MEMBERSET | EXPRFLAG.EXF_MASK_ANY))); EXPRFIELD rval = new EXPRFIELD(); rval.kind = ExpressionKind.EK_FIELD; rval.type = pType; rval.flags = nFlags; rval.SetOptionalObject(pOptionalObject); if (FWT != null) { rval.fwt = FWT; } Debug.Assert(rval != null); return (rval); }
public EXPRCAST CreateCast(EXPRFLAG nFlags, EXPRTYPEORNAMESPACE pType, EXPR pArg) { Debug.Assert(pArg != null); Debug.Assert(pType != null); Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY))); EXPRCAST rval = new EXPRCAST(); rval.type = pType.TypeOrNamespace as CType; rval.kind = ExpressionKind.EK_CAST; rval.Argument = pArg; rval.flags = nFlags; rval.DestinationType = pType; Debug.Assert(rval != null); return(rval); }
public BinOpArgInfo(EXPR op1, EXPR op2) { Debug.Assert(op1 != null); Debug.Assert(op2 != null); arg1 = op1; arg2 = op2; type1 = arg1.type; type2 = arg2.type; typeRaw1 = type1.StripNubs(); typeRaw2 = type2.StripNubs(); pt1 = type1.isPredefined() ? type1.getPredefType() : PredefinedType.PT_COUNT; pt2 = type2.isPredefined() ? type2.getPredefType() : PredefinedType.PT_COUNT; ptRaw1 = typeRaw1.isPredefined() ? typeRaw1.getPredefType() : PredefinedType.PT_COUNT; ptRaw2 = typeRaw2.isPredefined() ? typeRaw2.getPredefType() : PredefinedType.PT_COUNT; }
public EXPRARRINIT CreateArrayInit(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPR pOptionalArgumentDimensions, int[] pDimSizes) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY | EXPRFLAG.EXF_ARRAYCONST | EXPRFLAG.EXF_ARRAYALLCONST))); EXPRARRINIT rval = new EXPRARRINIT(); rval.kind = ExpressionKind.EK_ARRINIT; rval.type = pType; rval.SetOptionalArguments(pOptionalArguments); rval.SetOptionalArgumentDimensions(pOptionalArgumentDimensions); rval.dimSizes = pDimSizes; rval.dimSize = pDimSizes != null ? pDimSizes.Length : 0; Debug.Assert(rval != null); return(rval); }
public EXPRUNARYOP CreateUnaryOp(ExpressionKind exprKind, CType pType, EXPR pOperand) { Debug.Assert(exprKind.isUnaryOperator()); Debug.Assert(pOperand != null); EXPRUNARYOP rval = new EXPRUNARYOP(); rval.kind = exprKind; rval.type = pType; rval.flags = 0; rval.Child = pOperand; rval.OptionalUserDefinedCall = null; rval.UserDefinedCallMethod = null; Debug.Assert(rval != null); return(rval); }
public EXPREVENT CreateEvent(CType pType, EXPR pOptionalObject, EventWithType EWT) { EXPREVENT rval = new EXPREVENT(); rval.kind = ExpressionKind.EK_EVENT; rval.type = pType; rval.flags = 0; rval.OptionalObject = pOptionalObject; if (EWT != null) { rval.ewt = EWT; } Debug.Assert(rval != null); return(rval); }
///////////////////////////////////////////////////////////////////////////////// protected EXPRSTMT DispatchStatementList(EXPRSTMT expr) { Debug.Assert(expr != null); EXPRSTMT first = expr; EXPRSTMT pexpr = first; while (pexpr != null) { // If the processor replaces the statement -- potentially with // null, another statement, or a list of statements -- then we // make sure that the statement list is hooked together correctly. EXPRSTMT next = pexpr.GetOptionalNextStatement(); EXPRSTMT old = pexpr; // Unhook the next one. pexpr.SetOptionalNextStatement(null); EXPR result = Dispatch(pexpr); Debug.Assert(result == null || result.isSTMT()); if (pexpr == first) { first = (result == null) ? null : result.asSTMT(); } else { pexpr.SetOptionalNextStatement((result == null) ? null : result.asSTMT()); } // A transformation may return back a list of statements (or // if the statements have been determined to be unnecessary, // perhaps it has simply returned null.) // // Skip visiting the new list, then hook the tail of the old list // up to the end of the new list. while (pexpr.GetOptionalNextStatement() != null) { pexpr = pexpr.GetOptionalNextStatement(); } // Re-hook the next pointer. pexpr.SetOptionalNextStatement(next); } return(first); }
private bool bindImplicitConversionFromNullable(NullableType nubSrc) { // We can convert T? using a boxing conversion, we can convert it to ValueType, and // we can convert it to any interface implemented by T. // // 13.1.5 Boxing Conversions // // A nullable-type has a boxing conversion to the same set of types to which the nullable-type's // underlying type has boxing conversions. A boxing conversion applied to a value of a nullable-type // proceeds as follows: // // * If the HasValue property of the nullable value evaluates to false, then the result of the // boxing conversion is the null reference of the appropriate type. // // Otherwise, the result is obtained by boxing the result of evaluating the Value property on // the nullable value. AggregateType atsNub = nubSrc.GetAts(GetErrorContext()); if (atsNub == null) { return(false); } if (atsNub == _typeDest) { if (_needsExprDest) { _exprDest = _exprSrc; } return(true); } if (GetSymbolLoader().HasBaseConversion(nubSrc.GetUnderlyingType(), _typeDest) && !CConversions.FUnwrappingConv(nubSrc, _typeDest)) { if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_BOX); if (!_typeDest.isPredefType(PredefinedType.PT_OBJECT)) { // The base type of a nullable is always a non-nullable value type, // therefore so is typeDest unless typeDest is PT_OBJECT. In this case the conversion // needs to be unboxed. We only need this if we actually will use the result. _binder.bindSimpleCast(_exprDest, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } } return(true); } return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, nubSrc, _typeDest, _needsExprDest, out _exprDest, true)); }
public EXPRFIELD CreateField(EXPRFLAG nFlags, CType pType, EXPR pOptionalObject, uint nOffset, FieldWithType FWT, EXPR pOptionalLHS) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MEMBERSET | EXPRFLAG.EXF_MASK_ANY))); EXPRFIELD rval = new EXPRFIELD(); rval.kind = ExpressionKind.EK_FIELD; rval.type = pType; rval.flags = nFlags; rval.SetOptionalObject(pOptionalObject); if (FWT != null) { rval.fwt = FWT; } Debug.Assert(rval != null); return(rval); }
public EXPRBINOP CreateBinop(ExpressionKind exprKind, CType pType, EXPR p1, EXPR p2) { //Debug.Assert(exprKind.isBinaryOperator()); EXPRBINOP rval = new EXPRBINOP(); rval.kind = exprKind; rval.type = pType; rval.flags = EXPRFLAG.EXF_BINOP; rval.SetOptionalLeftChild(p1); rval.SetOptionalRightChild(p2); rval.isLifted = false; rval.SetOptionalUserDefinedCall(null); rval.SetUserDefinedCallMethod(null); Debug.Assert(rval != null); return(rval); }
public EXPRMEMGRP CreateMemGroup( EXPR pObject, MethPropWithInst mwi) { Name pName = mwi.Sym != null ? mwi.Sym.name : null; MethodOrPropertySymbol methProp = mwi.MethProp(); CType pType = mwi.GetType(); if (pType == null) { pType = GetTypes().GetErrorSym(); } return(CreateMemGroup(0, pName, mwi.TypeArgs, methProp != null ? methProp.getKind() : SYMKIND.SK_MethodSymbol, mwi.GetType(), methProp, pObject, new CMemberLookupResults(GetGlobalSymbols().AllocParams(1, new CType[] { pType }), pName))); }
public EXPRRETURN CreateReturn(EXPRFLAG nFlags, Scope pCurrentScope, EXPR pOptionalObject, EXPR pOptionalOriginalObject) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_ASLEAVE | EXPRFLAG.EXF_FINALLYBLOCKED | EXPRFLAG.EXF_RETURNISYIELD | EXPRFLAG.EXF_ASFINALLYLEAVE | EXPRFLAG.EXF_GENERATEDSTMT | EXPRFLAG.EXF_MARKING | EXPRFLAG.EXF_MASK_ANY ) )); EXPRRETURN rval = new EXPRRETURN(); rval.kind = ExpressionKind.EK_RETURN; rval.type = null; rval.flags = nFlags; rval.SetOptionalObject(pOptionalObject); Debug.Assert(rval != null); return(rval); }
public EXPR CreateOperator(ExpressionKind exprKind, CType pType, EXPR pArg1, EXPR pOptionalArg2) { Debug.Assert(pArg1 != null); EXPR rval = null; if (exprKind.isUnaryOperator()) { Debug.Assert(pOptionalArg2 == null); rval = CreateUnaryOp(exprKind, pType, pArg1); } else { rval = CreateBinop(exprKind, pType, pArg1, pOptionalArg2); } Debug.Assert(rval != null); return(rval); }
private bool bindExplicitConversionToTypeVar() { // 13.2.3 Explicit reference conversions // // For a type-parameter T that is known to be a reference type (25.7), the following // explicit reference conversions exist: // // * From the effective base class C of T to T and from any base class of C to T. // * From any interface-type to T. // * From a type-parameter U to T provided that T depends on U (25.7). Debug.Assert(_typeSrc != null); Debug.Assert(_typeDest != null); // NOTE: for the flags, we have to use EXPRFLAG.EXF_FORCE_UNBOX (not EXPRFLAG.EXF_REFCHECK) even when // we know that the type is a reference type. The verifier expects all code for // type parameters to behave as if the type parameter is a value type. // The jitter should be smart about it.... if (_typeSrc.isInterfaceType() || _binder.canConvert(_typeDest, _typeSrc, CONVERTTYPE.NOUDC)) { if (!_needsExprDest) { return(true); } // There is an explicit, possibly unboxing, conversion from Object or any interface to // a type variable. This will involve a type check and possibly an unbox. // There is an explicit conversion from non-interface X to the type var iff there is an // implicit conversion from the type var to X. if (_typeSrc.IsTypeParameterType()) { // Need to box first before unboxing. EXPR exprT; EXPRCLASS exprObj = GetExprFactory().MakeClass(_binder.GetReqPDT(PredefinedType.PT_OBJECT)); _binder.bindSimpleCast(_exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX); _exprSrc = exprT; } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } return(true); } return(false); }
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.getAggregate().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 // REVIEW: : 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 = GetExprFactory().CreateConstant(typeDest, ConstValFactory.GetDefaultValue(typeDest.constValKind())); } return(true); } return(false); }
// Value public EXPR BindValue(EXPR exprSrc) { Debug.Assert(exprSrc != null && exprSrc.type.IsNullableType()); // For new T?(x), the answer is x. if (CNullable.IsNullableConstructor(exprSrc)) { Debug.Assert(exprSrc.asCALL().GetOptionalArguments() != null && !exprSrc.asCALL().GetOptionalArguments().isLIST()); return(exprSrc.asCALL().GetOptionalArguments()); } CType typeBase = exprSrc.type.AsNullableType().GetUnderlyingType(); AggregateType ats = exprSrc.type.AsNullableType().GetAts(GetErrorContext()); if (ats == null) { EXPRPROP rval = GetExprFactory().CreateProperty(typeBase, exprSrc); rval.SetError(); return(rval); } // UNDONE: move this to transform pass ... PropertySymbol prop = GetSymbolLoader().getBSymmgr().propNubValue; if (prop == null) { prop = GetSymbolLoader().getPredefinedMembers().GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE); GetSymbolLoader().getBSymmgr().propNubValue = prop; } PropWithType pwt = new PropWithType(prop, ats); MethWithType mwt = new MethWithType(prop != null ? prop.methGet : null, ats); MethPropWithInst mpwi = new MethPropWithInst(prop, ats); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(exprSrc, mpwi); EXPRPROP exprRes = GetExprFactory().CreateProperty(typeBase, null, null, pMemGroup, pwt, mwt, null); if (prop == null) { exprRes.SetError(); } return(exprRes); }
public EXPRUSERDEFINEDCONVERSION CreateUserDefinedConversion(EXPR arg, EXPR call, MethWithInst mwi) { Debug.Assert(arg != null); Debug.Assert(call != null); EXPRUSERDEFINEDCONVERSION rval = new EXPRUSERDEFINEDCONVERSION(); rval.kind = ExpressionKind.EK_USERDEFINEDCONVERSION; rval.type = call.type; rval.flags = 0; rval.Argument = arg; rval.UserDefinedCall = call; rval.UserDefinedCallMethod = mwi; if (call.HasError()) { rval.SetError(); } Debug.Assert(rval != null); return(rval); }
public static IEnumerable <EXPR> ToEnumerable(this EXPR expr) { EXPR exprCur = expr; while (exprCur != null) { if (exprCur.isLIST()) { yield return(exprCur.asLIST().GetOptionalElement()); exprCur = exprCur.asLIST().GetOptionalNextListNode(); } else { yield return(exprCur); yield break; } } }
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); }
public EXPR Visit(EXPR pExpr) { if (pExpr == null) { return null; } EXPR pResult; if (IsCachedExpr(pExpr, out pResult)) { return pResult; } if (pExpr.isSTMT()) { return CacheExprMapping(pExpr, DispatchStatementList(pExpr.asSTMT())); } return CacheExprMapping(pExpr, Dispatch(pExpr)); }
public EXPRWRAP CreateWrap( Scope pCurrentScope, EXPR pOptionalExpression ) { EXPRWRAP rval = new EXPRWRAP(); rval.kind = ExpressionKind.EK_WRAP; rval.type = null; rval.flags = 0; rval.SetOptionalExpression(pOptionalExpression); if (pOptionalExpression != null) { rval.setType(pOptionalExpression.type); } rval.flags |= EXPRFLAG.EXF_LVALUE; Debug.Assert(rval != null); return(rval); }
public EXPRARRAYINDEX CreateArrayIndex(EXPR pArray, EXPR pIndex) { CType pType = pArray.type; if (pType != null && pType.IsArrayType()) { pType = pType.AsArrayType().GetElementType(); } else if (pType == null) { pType = GetTypes().GetReqPredefAgg(PredefinedType.PT_INT).getThisType(); } EXPRARRAYINDEX pResult = new EXPRARRAYINDEX(); pResult.kind = ExpressionKind.EK_ARRAYINDEX; pResult.type = pType; pResult.flags = 0; pResult.SetArray(pArray); pResult.SetIndex(pIndex); return(pResult); }
public EXPR Visit(EXPR pExpr) { if (pExpr == null) { return(null); } EXPR pResult; if (IsCachedExpr(pExpr, out pResult)) { return(pResult); } if (pExpr.isSTMT()) { return(CacheExprMapping(pExpr, DispatchStatementList(pExpr.asSTMT()))); } return(CacheExprMapping(pExpr, Dispatch(pExpr))); }
// Value public EXPR BindValue(EXPR exprSrc) { Debug.Assert(exprSrc != null && exprSrc.type.IsNullableType()); // For new T?(x), the answer is x. if (CNullable.IsNullableConstructor(exprSrc)) { Debug.Assert(exprSrc.asCALL().GetOptionalArguments() != null && !exprSrc.asCALL().GetOptionalArguments().isLIST()); return exprSrc.asCALL().GetOptionalArguments(); } CType typeBase = exprSrc.type.AsNullableType().GetUnderlyingType(); AggregateType ats = exprSrc.type.AsNullableType().GetAts(GetErrorContext()); if (ats == null) { EXPRPROP rval = GetExprFactory().CreateProperty(typeBase, exprSrc); rval.SetError(); return rval; } PropertySymbol prop = GetSymbolLoader().getBSymmgr().propNubValue; if (prop == null) { prop = GetSymbolLoader().getPredefinedMembers().GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE); GetSymbolLoader().getBSymmgr().propNubValue = prop; } PropWithType pwt = new PropWithType(prop, ats); MethWithType mwt = new MethWithType(prop != null ? prop.methGet : null, ats); MethPropWithInst mpwi = new MethPropWithInst(prop, ats); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(exprSrc, mpwi); EXPRPROP exprRes = GetExprFactory().CreateProperty(typeBase, null, null, pMemGroup, pwt, mwt, null); if (prop == null) { exprRes.SetError(); } return exprRes; }
public static bool IsNullableConstructor(EXPR expr) { Debug.Assert(expr != null); if (!expr.isCALL()) { return false; } EXPRCALL pCall = expr.asCALL(); if (pCall.GetMemberGroup().GetOptionalObject() != null) { return false; } MethodSymbol meth = pCall.mwi.Meth(); if (meth == null) { return false; } return meth.IsNullableConstructor(); }
public EXPRPROP CreateProperty(CType pType, EXPR pOptionalObjectThrough, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, PropWithType pwtSlot, MethWithType mwtGet, MethWithType mwtSet) { EXPRPROP rval = new EXPRPROP(); rval.kind = ExpressionKind.EK_PROP; rval.type = pType; rval.flags = 0; rval.SetOptionalObjectThrough(pOptionalObjectThrough); rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); if (pwtSlot != null) { rval.pwtSlot = pwtSlot; } if (mwtSet != null) { rval.mwtSet = mwtSet; } Debug.Assert(rval != null); return(rval); }
private bool bindExplicitConversionFromNub() { Debug.Assert(_typeSrc != null); Debug.Assert(_typeDest != null); // If S and T are value types and there is a builtin conversion from S => T then there is an // explicit conversion from S? => T that throws on null. if (_typeDest.IsValType() && _binder.BindExplicitConversion(null, _typeSrc.StripNubs(), _exprTypeDest, _pDestinationTypeForLambdaErrorReporting, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { EXPR valueSrc = _exprSrc; // This is a holdover from the days when you could have nullable of nullable. // Can we remove this loop? while (valueSrc.type.IsNullableType()) { valueSrc = _binder.BindNubValue(valueSrc); } Debug.Assert(valueSrc.type == _typeSrc.StripNubs()); if (!_binder.BindExplicitConversion(valueSrc, valueSrc.type, _exprTypeDest, _pDestinationTypeForLambdaErrorReporting, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { VSFAIL("BindExplicitConversion failed unexpectedly"); return(false); } if (_exprDest.kind == ExpressionKind.EK_USERDEFINEDCONVERSION) { _exprDest.asUSERDEFINEDCONVERSION().Argument = _exprSrc; } } return(true); } if ((_flags & CONVERTTYPE.NOUDC) == 0) { return(_binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false)); } return(false); }
public EXPRQUESTIONMARK CreateQuestionMark(EXPR pTestExpression, EXPRBINOP pConsequence) { Debug.Assert(pTestExpression != null); Debug.Assert(pConsequence != null); CType pType = pConsequence.type; if (pType == null) { Debug.Assert(pConsequence.GetOptionalLeftChild() != null); pType = pConsequence.GetOptionalLeftChild().type; Debug.Assert(pType != null); } EXPRQUESTIONMARK pResult = new EXPRQUESTIONMARK(); pResult.kind = ExpressionKind.EK_QUESTIONMARK; pResult.type = pType; pResult.flags = 0; pResult.SetTestExpression(pTestExpression); pResult.SetConsequence(pConsequence); Debug.Assert(pResult != null); return(pResult); }
public EXPRCALL CreateCall(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); EXPRCALL rval = new EXPRCALL(); rval.kind = ExpressionKind.EK_CALL; rval.type = pType; rval.flags = nFlags; rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); rval.nubLiftKind = NullableCallLiftKind.NotLifted; rval.castOfNonLiftedResultToLiftedType = null; rval.mwi = MWI; Debug.Assert(rval != null); return (rval); }
public EXPRCALL BindNew(EXPR pExprSrc) { Debug.Assert(pExprSrc != null); NullableType pNubSourceType = GetSymbolLoader().GetTypeManager().GetNullable(pExprSrc.type); AggregateType pSourceType = pNubSourceType.GetAts(GetErrorContext()); if (pSourceType == null) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(pExprSrc, mwi); EXPRCALL rval = GetExprFactory().CreateCall(0, pNubSourceType, null, pMemGroup, null); rval.SetError(); return(rval); } // UNDONE: move this to transform pass MethodSymbol meth = GetSymbolLoader().getBSymmgr().methNubCtor; if (meth == null) { meth = GetSymbolLoader().getPredefinedMembers().GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); GetSymbolLoader().getBSymmgr().methNubCtor = meth; } MethWithInst methwithinst = new MethWithInst(meth, pSourceType, BSYMMGR.EmptyTypeArray()); EXPRMEMGRP memgroup = GetExprFactory().CreateMemGroup(null, methwithinst); EXPRCALL pExprRes = GetExprFactory().CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, pExprSrc, memgroup, methwithinst); if (meth == null) { pExprRes.SetError(); } return(pExprRes); }
public static bool IsNullableConstructor(EXPR expr) { Debug.Assert(expr != null); if (!expr.isCALL()) { return(false); } EXPRCALL pCall = expr.asCALL(); if (pCall.GetMemberGroup().GetOptionalObject() != null) { return(false); } MethodSymbol meth = pCall.mwi.Meth(); if (meth == null) { return(false); } return(meth.IsNullableConstructor()); }
///////////////////////////////////////////////////////////////////////////////// public static Expression Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable<Expression> listOfParameters) { ExpressionTreeCallRewriter rewriter = new ExpressionTreeCallRewriter(typeManager, listOfParameters); // We should have a EXPRBINOP thats an EK_SEQUENCE. The RHS of our sequence // should be a call to PM_EXPRESSION_LAMBDA. The LHS of our sequence is the // set of declarations for the parameters that we'll need. // Assert all of these first, and then unwrap them. Debug.Assert(pExpr != null); Debug.Assert(pExpr.isBIN()); Debug.Assert(pExpr.kind == ExpressionKind.EK_SEQUENCE); Debug.Assert(pExpr.asBIN().GetOptionalRightChild() != null); Debug.Assert(pExpr.asBIN().GetOptionalRightChild().isCALL()); Debug.Assert(pExpr.asBIN().GetOptionalRightChild().asCALL().PredefinedMethod == PREDEFMETH.PM_EXPRESSION_LAMBDA); Debug.Assert(pExpr.asBIN().GetOptionalLeftChild() != null); // Visit the left to generate the parameter construction. rewriter.Visit(pExpr.asBIN().GetOptionalLeftChild()); EXPRCALL call = pExpr.asBIN().GetOptionalRightChild().asCALL(); ExpressionEXPR e = rewriter.Visit(call) as ExpressionEXPR; return e.Expression; }
public EXPRCALL CreateCall(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); EXPRCALL rval = new EXPRCALL(); rval.kind = ExpressionKind.EK_CALL; rval.type = pType; rval.flags = nFlags; rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); rval.nubLiftKind = NullableCallLiftKind.NotLifted; rval.castOfNonLiftedResultToLiftedType = null; rval.mwi = MWI; Debug.Assert(rval != null); return(rval); }
public void setArgs(EXPR args) { RETAILVERIFY(this.isCALL() || this.isPROP() || this.isFIELD() || this.isARRAYINDEX()); if (this.isFIELD()) { Debug.Assert(false, "Setting arguments on a field."); return; } switch (kind) { case ExpressionKind.EK_CALL: this.asCALL().SetOptionalArguments(args); return; case ExpressionKind.EK_PROP: this.asPROP().SetOptionalArguments(args); return; case ExpressionKind.EK_ARRAYINDEX: this.asARRAYINDEX().SetIndex(args); return; } Debug.Assert(false, "Shouldn't get here without a CALL, PROP, FIELD or ARRINDEX"); }
protected virtual EXPR GenerateConversionWithSource(EXPR pTarget, CType pType, bool bChecked) { PREDEFMETH pdm = bChecked ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT; EXPR pTypeOf = CreateTypeOf(pType); return GenerateCall(pdm, pTarget, pTypeOf); }
protected virtual EXPR GenerateValueAccessConversion(EXPR pArgument) { Debug.Assert(pArgument != null); CType pStrippedTypeOfArgument = pArgument.type.StripNubs(); EXPR pStrippedTypeExpr = CreateTypeOf(pStrippedTypeOfArgument); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, Visit(pArgument), pStrippedTypeExpr); }
protected virtual EXPR GenerateBuiltInUnaryOperator(PREDEFMETH pdm, EXPR pOriginalOperator, EXPR pOperator) { EXPR op = Visit(pOriginalOperator); if (pOriginalOperator.type.IsNullableType() && pOriginalOperator.type.StripNubs().isEnumType()) { Debug.Assert(pOperator.kind == ExpressionKind.EK_BITNOT); // The only built-in unary operator defined on nullable enum. CType underlyingType = pOriginalOperator.type.StripNubs().underlyingEnumType(); CType nullableType = GetSymbolLoader().GetTypeManager().GetNullable(underlyingType); op = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, op, CreateTypeOf(nullableType)); } EXPR call = GenerateCall(pdm, op); if (pOriginalOperator.type.IsNullableType() && pOriginalOperator.type.StripNubs().isEnumType()) { call = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, call, CreateTypeOf(pOperator.type)); } return call; }
protected virtual EXPR GenerateConversion(EXPR arg, CType CType, bool bChecked) { return GenerateConversionWithSource(Visit(arg), CType, bChecked || arg.isChecked()); }
/*************************************************************************************************** * Lookup must be called before anything else can be called. * * typeSrc - Must be an AggregateType or TypeParameterType. * obj - the expression through which the member is being accessed. This is used for accessibility * of protected members and for constructing a MEMGRP from the results of the lookup. * It is legal for obj to be an EK_CLASS, in which case it may be used for accessibility, but * will not be used for MEMGRP construction. * symWhere - the symbol from with the name is being accessed (for checking accessibility). * name - the name to look for. * arity - the number of type args specified. Only members that support this arity are found. * Note that when arity is zero, all methods are considered since we do type argument * inferencing. * * flags - See MemLookFlags. * TypeVarsAllowed only applies to the most derived type (not base types). ***************************************************************************************************/ public bool Lookup(CSemanticChecker checker, CType typeSrc, EXPR obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags) { Debug.Assert((flags & ~MemLookFlags.All) == 0); Debug.Assert(obj == null || obj.type != null); Debug.Assert(typeSrc.IsAggregateType() || typeSrc.IsTypeParameterType()); Debug.Assert(checker != null); _prgtype = _rgtypeStart; // Save the inputs for error handling, etc. _pSemanticChecker = checker; _pSymbolLoader = checker.GetSymbolLoader(); _typeSrc = typeSrc; _obj = (obj != null && !obj.isCLASS()) ? obj : null; _symWhere = symWhere; _name = name; _arity = arity; _flags = flags; if ((_flags & MemLookFlags.BaseCall) != 0) { _typeQual = null; } else if ((_flags & MemLookFlags.Ctor) != 0) { _typeQual = _typeSrc; } else if (obj != null) { _typeQual = (CType)obj.type; } else { _typeQual = null; } // Determine what to search. AggregateType typeCls1 = null; AggregateType typeIface = null; TypeArray ifaces = BSYMMGR.EmptyTypeArray(); AggregateType typeCls2 = null; if (typeSrc.IsTypeParameterType()) { Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall | MemLookFlags.TypeVarsAllowed)) == 0); _flags &= ~MemLookFlags.TypeVarsAllowed; ifaces = typeSrc.AsTypeParameterType().GetInterfaceBounds(); typeCls1 = typeSrc.AsTypeParameterType().GetEffectiveBaseClass(); if (ifaces.size > 0 && typeCls1.isPredefType(PredefinedType.PT_OBJECT)) { typeCls1 = null; } } else if (!typeSrc.isInterfaceType()) { typeCls1 = typeSrc.AsAggregateType(); if (typeCls1.IsWindowsRuntimeType()) { ifaces = typeCls1.GetWinRTCollectionIfacesAll(GetSymbolLoader()); } } else { Debug.Assert(typeSrc.isInterfaceType()); Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0); typeIface = typeSrc.AsAggregateType(); ifaces = typeIface.GetIfacesAll(); } if (typeIface != null || ifaces.size > 0) { typeCls2 = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_OBJECT); } // Search the class first (except possibly object). if (typeCls1 == null || LookupInClass(typeCls1, ref typeCls2)) { // Search the interfaces. if ((typeIface != null || ifaces.size > 0) && LookupInInterfaces(typeIface, ifaces) && typeCls2 != null) { // Search object last. Debug.Assert(typeCls2 != null && typeCls2.isPredefType(PredefinedType.PT_OBJECT)); AggregateType result = null; LookupInClass(typeCls2, ref result); } } // if we are requested with extension methods _results = new CMemberLookupResults(GetAllTypes(), _name); return(!FError()); }
/*************************************************************************************************** * 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(GetErrorContext()); if (atsDst == null) { return(false); } // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), 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, exprTypeDest, out exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } int cnubDst; int cnubSrc; CType typeDstBase = nubDst.StripNubs(out cnubDst); EXPRCLASS exprTypeDstBase = GetExprFactory().MakeClass(typeDstBase); CType typeSrcBase = typeSrc.StripNubs(out cnubSrc); ConversionFunc pfn = (flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)binder.BindExplicitConversion : (ConversionFunc)binder.BindImplicitConversion; if (cnubSrc == 0) { Debug.Assert(typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (typeSrc.IsNullType()) { // If we have the constant null, generate it as a default value of T?. If we have // some crazy 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) { if (exprSrc.isCONSTANT_OK()) { exprDest = GetExprFactory().CreateZeroInit(nubDst); } else { exprDest = GetExprFactory().CreateCast(0x00, 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, exprTypeDstBase, nubDst, needsExprDest, out exprTmp, flags | CONVERTTYPE.NOUDC)) { if (needsExprDest) { // UNDONE: This is a premature realization of the nullable conversion as // UNDONE: a constructor. Rather than flagging this, can we simply emit it // UNDONE: as a cast node and have the operator rewrite pass turn it into // UNDONE: a constructor call? EXPRUSERDEFINEDCONVERSION exprUDC = exprTmp.kind == ExpressionKind.EK_USERDEFINEDCONVERSION ? exprTmp.asUSERDEFINEDCONVERSION() : null; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } // This logic is left over from the days when T?? was legal. However there are error/LAF cases that necessitates the loop. // typeSrc is not nullable so just wrap the required number of times. For legal code (cnubDst <= 0). for (int i = 0; i < cnubDst; i++) { exprTmp = binder.BindNubNew(exprTmp); exprTmp.asCALL().nubLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprUDC.setType((CType)exprTmp.type); 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, exprTypeDstBase, nubDst, 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); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL exprDst = GetExprFactory().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); EXPRCLASS arg2 = GetExprFactory().MakeClass(typeDstBase); bool convertible; if (0 != (flags & CONVERTTYPE.ISEXPLICIT)) { convertible = binder.BindExplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, flags | CONVERTTYPE.NOUDC); } else { convertible = binder.BindImplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, flags | CONVERTTYPE.NOUDC); } if (!convertible) { VSFAIL("bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } exprDst.castOfNonLiftedResultToLiftedType = binder.mustCast(arg1, nubDst, 0); exprDst.nubLiftKind = NullableCallLiftKind.NullableConversion; exprDst.pConversions = exprDst.castOfNonLiftedResultToLiftedType; exprDest = exprDst; } return(true); }
protected void FixLiftedUserDefinedBinaryOperators(EXPRBINOP expr, ref EXPR pp1, ref EXPR pp2) { // If we have lifted T1 op T2 to T1? op T2?, and we have an expression T1 op T2? or T1? op T2 then // we need to ensure that the unlifted actual arguments are promoted to their nullable CType. Debug.Assert(expr != null); Debug.Assert(pp1 != null); Debug.Assert(pp1 != null); Debug.Assert(pp2 != null); Debug.Assert(pp2 != null); MethodSymbol method = expr.GetUserDefinedCallMethod().Meth(); EXPR orig1 = expr.GetOptionalLeftChild(); EXPR orig2 = expr.GetOptionalRightChild(); Debug.Assert(orig1 != null && orig2 != null); EXPR new1 = pp1; EXPR new2 = pp2; CType fptype1 = method.Params.Item(0); CType fptype2 = method.Params.Item(1); CType aatype1 = orig1.type; CType aatype2 = orig2.type; // Is the operator even a candidate for lifting? if (fptype1.IsNullableType() || fptype2.IsNullableType() || !fptype1.IsAggregateType() || !fptype2.IsAggregateType() || !fptype1.AsAggregateType().getAggregate().IsValueType() || !fptype2.AsAggregateType().getAggregate().IsValueType()) { return; } CType nubfptype1 = GetSymbolLoader().GetTypeManager().GetNullable(fptype1); CType nubfptype2 = GetSymbolLoader().GetTypeManager().GetNullable(fptype2); // If we have null op X, or T1 op T2?, or T1 op null, lift first arg to T1? if (aatype1.IsNullType() || aatype1 == fptype1 && (aatype2 == nubfptype2 || aatype2.IsNullType())) { new1 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, new1, CreateTypeOf(nubfptype1)); } // If we have X op null, or T1? op T2, or null op T2, lift second arg to T2? if (aatype2.IsNullType() || aatype2 == fptype2 && (aatype1 == nubfptype1 || aatype1.IsNullType())) { new2 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, new2, CreateTypeOf(nubfptype2)); } pp1 = new1; pp2 = new2; }
protected virtual EXPR GenerateUserDefinedConversion(EXPRUSERDEFINEDCONVERSION pExpr, EXPR pArgument) { EXPR pCastCall = pExpr.UserDefinedCall; EXPR pCastArgument = pExpr.Argument; EXPR pConversionSource = null; if (!isEnumToDecimalConversion(pArgument.type, pExpr.type) && IsNullableValueAccess(pCastArgument, pArgument)) { // We have an implicit conversion of nullable CType to the value CType, generate a convert node for it. pConversionSource = GenerateValueAccessConversion(pArgument); } else if (pCastCall.isCALL() && pCastCall.asCALL().pConversions != null) { EXPR pUDConversion = pCastCall.asCALL().pConversions; if (pUDConversion.isCALL()) { EXPR pUDConversionArgument = pUDConversion.asCALL().GetOptionalArguments(); if (IsNullableValueAccess(pUDConversionArgument, pArgument)) { pConversionSource = GenerateValueAccessConversion(pArgument); } else { pConversionSource = Visit(pUDConversionArgument); } return GenerateConversionWithSource(pConversionSource, pCastCall.type, pCastCall.asCALL().isChecked()); } else { // This can happen if we have a UD conversion from C to, say, int, // and we have an explicit cast to decimal?. The conversion should // then be bound as two chained user-defined conversions. Debug.Assert(pUDConversion.isUSERDEFINEDCONVERSION()); // Just recurse. return GenerateUserDefinedConversion(pUDConversion.asUSERDEFINEDCONVERSION(), pArgument); } } else { pConversionSource = Visit(pCastArgument); } return GenerateUserDefinedConversion(pCastArgument, pExpr.type, pConversionSource, pExpr.UserDefinedCallMethod); }
protected EXPRCALL GenerateCall(PREDEFMETH pdm, EXPR arg1, EXPR arg2, EXPR arg3, EXPR arg4) { MethodSymbol method = GetPreDefMethod(pdm); if (method == null) return null; AggregateType expressionType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); EXPR args = GetExprFactory().CreateList(arg1, arg2, arg3, arg4); MethWithInst mwi = new MethWithInst(method, expressionType); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi); call.PredefinedMethod = pdm; return call; }
protected virtual EXPRARRINIT GenerateParamsArray(EXPR args, PredefinedType pt) { int parameterCount = ExpressionIterator.Count(args); AggregateType paramsArrayElementType = GetSymbolLoader().GetOptPredefTypeErr(pt, true); ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1); EXPRCONSTANT paramsArrayArg = GetExprFactory().CreateIntegerConstant(parameterCount); EXPRARRINIT arrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, paramsArrayType, args, paramsArrayArg, null); arrayInit.dimSize = parameterCount; arrayInit.dimSizes = new int[] { arrayInit.dimSize }; // CLEANUP: Why isn't this done by the factory? return arrayInit; }
protected EXPRCALL GenerateCall(PREDEFMETH pdm, EXPR arg1) { MethodSymbol method = GetPreDefMethod(pdm); // this should be enforced in an earlier pass and the tranform pass should not // be handeling this error if (method == null) return null; AggregateType expressionType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); MethWithInst mwi = new MethWithInst(method, expressionType); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi); call.PredefinedMethod = pdm; return call; }
protected virtual EXPR GenerateConstant(EXPR expr) { EXPRFLAG flags = 0; AggregateType pObject = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_OBJECT, true); if (expr.type.IsNullType()) { EXPRTYPEOF pTypeOf = CreateTypeOf(pObject); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, expr, pTypeOf); } AggregateType stringType = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_STRING, true); if (expr.type != stringType) { flags = EXPRFLAG.EXF_BOX; } EXPRCLASS objectType = GetExprFactory().MakeClass(pObject); EXPRCAST cast = GetExprFactory().CreateCast(flags, objectType, expr); EXPRTYPEOF pTypeOf2 = CreateTypeOf(expr.type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, cast, pTypeOf2); }
protected virtual EXPR GenerateIndexList(EXPR oldIndices) { CType intType = symbolLoader.GetReqPredefType(PredefinedType.PT_INT, true); EXPR newIndices = null; EXPR newIndicesTail = newIndices; for (ExpressionIterator it = new ExpressionIterator(oldIndices); !it.AtEnd(); it.MoveNext()) { EXPR newIndex = it.Current(); if (newIndex.type != intType) { EXPRCLASS exprType = expressionFactory.CreateClass(intType, null, null); newIndex = expressionFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, exprType, newIndex); newIndex.flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } EXPR rewrittenIndex = Visit(newIndex); expressionFactory.AppendItemToList(rewrittenIndex, ref newIndices, ref newIndicesTail); } return newIndices; }
protected virtual EXPR GenerateUserDefinedConversion(EXPR arg, CType type, MethWithInst method) { EXPR target = Visit(arg); return GenerateUserDefinedConversion(arg, type, target, method); }
protected bool IsNullableValueAccess(EXPR pExpr, EXPR pObject) { Debug.Assert(pExpr != null); return pExpr.isPROP() && (pExpr.asPROP().GetMemberGroup().GetOptionalObject() == pObject) && pObject.type.IsNullableType(); }
protected virtual 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 = GetSymbolLoader().GetTypeManager().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 = GetSymbolLoader().GetTypeManager().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 = GetExprFactory().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); }
protected bool IsDelegateConstructorCall(EXPR pExpr) { Debug.Assert(pExpr != null); if (!pExpr.isCALL()) { return false; } EXPRCALL pCall = pExpr.asCALL(); return pCall.mwi.Meth() != null && pCall.mwi.Meth().IsConstructor() && pCall.type.isDelegateType() && pCall.GetOptionalArguments() != null && pCall.GetOptionalArguments().isLIST() && pCall.GetOptionalArguments().asLIST().GetOptionalNextListNode().kind == ExpressionKind.EK_FUNCPTR; }
protected EXPR DestroyWraps(EXPRBOUNDLAMBDA anonmeth, EXPR sequence) { for (Symbol sym = anonmeth.ArgumentScope(); sym != null; sym = sym.nextChild) { if (!sym.IsLocalVariableSymbol()) { continue; } LocalVariableSymbol local = sym.AsLocalVariableSymbol(); if (local.isThis) { continue; } Debug.Assert(local.wrap != null); Debug.Assert(anonmeth.OptionalBody != null); EXPR freeWrap = GetExprFactory().CreateWrap(anonmeth.OptionalBody.OptionalScopeSymbol, local.wrap); sequence = GetExprFactory().CreateReverseSequence(sequence, freeWrap); } return sequence; }
protected virtual EXPR GenerateQuestionMarkOperand(EXPR pExpr) { Debug.Assert(pExpr != null); // We must not optimize away compiler-generated reference casts because // the expression tree API insists that the CType of both sides be identical. if (pExpr.isCAST()) { return GenerateConversion(pExpr.asCAST().GetArgument(), pExpr.type, pExpr.isChecked()); } return Visit(pExpr); }
///////////////////////////////////////////////////////////////////////////////// internal SymWithType LookupMember( string name, EXPR callingObject, ParentSymbol context, int arity, MemberLookup mem, bool allowSpecialNames, bool requireInvocable) { CType type = callingObject.type; if (type.IsArrayType()) { type = _semanticChecker.GetSymbolLoader().GetReqPredefType(PredefinedType.PT_ARRAY); } if (type.IsNullableType()) { type = type.AsNullableType().GetAts(_semanticChecker.GetSymbolLoader().GetErrorContext()); } if (!mem.Lookup( _semanticChecker, type, callingObject, context, GetName(name), arity, MemLookFlags.TypeVarsAllowed | (allowSpecialNames ? 0 : MemLookFlags.UserCallable) | (name == SpecialNames.Indexer ? MemLookFlags.Indexer : 0) | (name == SpecialNames.Constructor ? MemLookFlags.Ctor : 0) | (requireInvocable ? MemLookFlags.MustBeInvocable : 0))) { return null; } return mem.SwtFirst(); }
/* * BindImplicitConversion * * This is a complex routine with complex parameters. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with implicit conversions. * * exprSrc - the expression being converted. Can be null if only type conversion * info is being supplied. * typeSrc - type of the source * typeDest - type of the destination * exprDest - returns an expression of the src converted to the dest. If null, we * only care about whether the conversion can be attempted, not the * expression tree. * flags - flags possibly customizing the conversions allowed. E.g., can suppress * user-defined conversions. * * returns true if the conversion can be made, false if not. */ public bool Bind() { // 13.1 Implicit conversions // // The following conversions are classified as implicit conversions: // // * Identity conversions // * Implicit numeric conversions // * Implicit enumeration conversions // * Implicit reference conversions // * Boxing conversions // * Implicit type parameter conversions // * Implicit constant expression conversions // * User-defined implicit conversions // * Implicit conversions from an anonymous method expression to a compatible delegate type // * Implicit conversion from a method group to a compatible delegate type // * Conversions from the null type (11.2.7) to any nullable type // * Implicit nullable conversions // * Lifted user-defined implicit conversions // // Implicit conversions can occur in a variety of situations, including function member invocations // (14.4.3), cast expressions (14.6.6), and assignments (14.14). // Can't convert to or from the error type. if (typeSrc == null || typeDest == null || typeDest.IsNeverSameType()) { return(false); } Debug.Assert(typeSrc != null && typeDest != null); // types must be supplied. Debug.Assert(exprSrc == null || typeSrc == exprSrc.type); // type of source should be correct if source supplied Debug.Assert(!needsExprDest || exprSrc != null); // need source expr to create dest expr switch (typeDest.GetTypeKind()) { case TypeKind.TK_ErrorType: Debug.Assert(typeDest.AsErrorType().HasTypeParent() || typeDest.AsErrorType().HasNSParent()); if (typeSrc != typeDest) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_NullType: // Can only convert to the null type if src is null. if (!typeSrc.IsNullType()) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_MethodGroupType: VSFAIL("Something is wrong with Type.IsNeverSameType()"); return(false); case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_ArgumentListType: return(typeSrc == typeDest); case TypeKind.TK_VoidType: return(false); default: break; } if (typeSrc.IsErrorType()) { Debug.Assert(!typeDest.IsErrorType()); return(false); } // 13.1.1 Identity conversion // // An identity conversion converts from any type to the same type. This conversion exists only // such that an entity that already has a required type can be said to be convertible to that type. if (typeSrc == typeDest && ((flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!typeSrc.isPredefType(PredefinedType.PT_FLOAT) && !typeSrc.isPredefType(PredefinedType.PT_DOUBLE)))) { if (needsExprDest) { exprDest = exprSrc; } return(true); } if (typeDest.IsNullableType()) { return(BindNubConversion(typeDest.AsNullableType())); } if (typeSrc.IsNullableType()) { return(bindImplicitConversionFromNullable(typeSrc.AsNullableType())); } if ((flags & CONVERTTYPE.ISEXPLICIT) != 0) { flags |= CONVERTTYPE.NOUDC; } // Get the fundamental types of destination. FUNDTYPE ftDest = typeDest.fundType(); Debug.Assert(ftDest != FUNDTYPE.FT_NONE || typeDest.IsParameterModifierType()); switch (typeSrc.GetTypeKind()) { default: VSFAIL("Bad type symbol kind"); break; case TypeKind.TK_MethodGroupType: if (exprSrc.isMEMGRP()) { EXPRCALL outExpr; bool retVal = binder.BindGrpConversion(exprSrc.asMEMGRP(), typeDest, needsExprDest, out outExpr, false); exprDest = outExpr; return(retVal); } return(false); case TypeKind.TK_VoidType: case TypeKind.TK_ErrorType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArgumentListType: return(false); case TypeKind.TK_NullType: if (bindImplicitConversionFromNull()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_ArrayType: if (bindImplicitConversionFromArray()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_PointerType: if (bindImplicitConversionFromPointer()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_TypeParameterType: if (bindImplicitConversionFromTypeVar(typeSrc.AsTypeParameterType())) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_AggregateType: // TypeReference and ArgIterator can't be boxed (or converted to anything else) if (typeSrc.isSpecialByRefType()) { return(false); } if (bindImplicitConversionFromAgg(typeSrc.AsAggregateType())) { return(true); } // If not, try user defined implicit conversions. break; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Every incoming dynamic operand should be implicitly convertible // to any type that it is an instance of. if (exprSrc != null && exprSrc.RuntimeObject != null && typeDest.AssociatedSystemType.IsInstanceOfType(exprSrc.RuntimeObject) && binder.GetSemanticChecker().CheckTypeAccess(typeDest, binder.Context.ContextForMemberLookup())) { if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, exprSrc.flags & EXPRFLAG.EXF_CANTBENULL); } return(true); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // END RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // 13.1.8 User-defined implicit conversions // // A user-defined implicit conversion consists of an optional standard implicit conversion, // followed by execution of a user-defined implicit conversion operator, followed by another // optional standard implicit conversion. The exact rules for evaluating user-defined // conversions are described in 13.4.3. if (0 == (flags & CONVERTTYPE.NOUDC)) { return(binder.bindUserDefinedConversion(exprSrc, typeSrc, typeDest, needsExprDest, out exprDest, true)); } // No conversion was found. return(false); }