public GroupToArgsBinder(ExpressionBinder exprBinder, BindingFlag bindFlags, EXPRMEMGRP grp, ArgInfos args, ArgInfos originalArgs, bool bHasNamedArguments, AggregateType atsDelegate) { Debug.Assert(grp != null); Debug.Assert(exprBinder != null); Debug.Assert(args != null); _pExprBinder = exprBinder; _fCandidatesUnsupported = false; _fBindFlags = bindFlags; _pGroup = grp; _pArguments = args; _pOriginalArguments = originalArgs; _bHasNamedArguments = bHasNamedArguments; _pDelegate = atsDelegate; _pCurrentType = null; _pCurrentSym = null; _pCurrentTypeArgs = null; _pCurrentParameters = null; _pBestParameters = null; _nArgBest = -1; _nWrongCount = 0; _bIterateToEndOfNsList = false; _bBindingCollectionAddArgs = false; _results = new GroupToArgsBinderResult(); _methList = new List<CandidateFunctionMember>(); _mpwiParamTypeConstraints = new MethPropWithInst(); _mpwiBogus = new MethPropWithInst(); _mpwiCantInferInstArg = new MethPropWithInst(); _mwtBadArity = new MethWithType(); _HiddenTypes = new List<CType>(); }
public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType @object, CType qualifyingType, Declaration context, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask) { Debug.Assert(name != null); Debug.Assert(symLoader != null); Debug.Assert(checker != null); Debug.Assert(containingTypes != null); _pSemanticChecker = checker; _pSymbolLoader = symLoader; _pCurrentType = null; _pCurrentSym = null; _pName = name; _pContainingTypes = containingTypes; _pQualifyingType = qualifyingType; _pContext = context; _bAllowBogusAndInaccessible = allowBogusAndInaccessible; _bAllowExtensionMethods = allowExtensionMethods; _nArity = arity; _flags = flags; _mask = mask; _nCurrentTypeCount = 0; _bIsCheckingInstanceMethods = true; _bAtEnd = false; _bCurrentSymIsBogus = false; _bCurrentSymIsInaccessible = false; _bcanIncludeExtensionsInResults = _bAllowExtensionMethods; _bEndIterationAtCurrentExtensionList = false; }
public virtual ACCESSERROR CheckAccess2(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { Debug.Assert(symCheck != null); Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate()); Debug.Assert(typeThru == null || typeThru.IsAggregateType() || typeThru.IsTypeParameterType() || typeThru.IsArrayType() || typeThru.IsNullableType() || typeThru.IsErrorType()); #if DEBUG switch (symCheck.getKind()) { default: break; case SYMKIND.SK_MethodSymbol: case SYMKIND.SK_PropertySymbol: case SYMKIND.SK_FieldSymbol: case SYMKIND.SK_EventSymbol: Debug.Assert(atsCheck != null); break; } #endif // DEBUG ACCESSERROR error = CheckAccessCore(symCheck, atsCheck, symWhere, typeThru); if (ACCESSERROR.ACCESSERROR_NOERROR != error) { return error; } // Check the accessibility of the return CType. CType CType = symCheck.getType(); if (CType == null) { return ACCESSERROR.ACCESSERROR_NOERROR; } // For members of AGGSYMs, atsCheck should always be specified! Debug.Assert(atsCheck != null); if (atsCheck.getAggregate().IsSource()) { // We already check the "at least as accessible as" rules. // Does this always work for generics? // Could we get a bad CType argument in typeThru? // Maybe call CheckTypeAccess on typeThru? return ACCESSERROR.ACCESSERROR_NOERROR; } // Substitute on the CType. if (atsCheck.GetTypeArgsAll().size > 0) { CType = SymbolLoader.GetTypeManager().SubstType(CType, atsCheck); } return CheckTypeAccess(CType, symWhere) ? ACCESSERROR.ACCESSERROR_NOERROR : ACCESSERROR.ACCESSERROR_NOACCESS; }
public void SetBounds(TypeArray pBounds) { _pBounds = pBounds; _pInterfaceBounds = null; _pEffectiveBaseClass = null; _pDeducedBaseClass = null; _bHasRefBound = false; _bHasValBound = false; }
///////////////////////////////////////////////////////////////////////////////// public void AddInconvertibleResult( MethodSymbol method, AggregateType currentType, TypeArray currentTypeArgs) { if (InconvertibleResult.Sym == null) { // This is the first one, so set it for error reporting usage. InconvertibleResult.Set(method, currentType, currentTypeArgs); } _inconvertibleResults.Add(new MethPropWithInst(method, currentType, currentTypeArgs)); }
// Aggregate public AggregateType CreateAggregateType( Name name, AggregateSymbol parent, TypeArray typeArgsThis, AggregateType outerType) { AggregateType type = new AggregateType(); type.outerType = outerType; type.SetOwningAggregate(parent); type.SetTypeArgsThis(typeArgsThis); type.SetName(name); type.SetTypeKind(TypeKind.TK_AggregateType); return type; }
public AggregateType GetAts(ErrorHandling errorContext) { AggregateSymbol aggNullable = typeManager.GetNullable(); if (aggNullable == null) { throw Error.InternalCompilerError(); } if (ats == null) { CType typePar = GetUnderlyingType(); CType[] typeParArray = new CType[] { typePar }; TypeArray ta = symmgr.AllocParams(1, typeParArray); ats = typeManager.GetAggregate(aggNullable, ta); } return ats; }
public AggregateType GetBaseClass() { #if CSEE AggregateType atsBase = getAggregate().GetBaseClass(); if (!atsBase || GetTypeArgsAll().size == 0 || atsBase.GetTypeArgsAll().size == 0) return atsBase; return getAggregate().GetTypeManager().SubstType(atsBase, GetTypeArgsAll()).AsAggregateType(); #else // !CSEE if (_baseType == null) { _baseType = getAggregate().GetTypeManager().SubstType(getAggregate().GetBaseClass(), GetTypeArgsAll()) as AggregateType; } return _baseType; #endif // !CSEE }
public AggregateType GetAts(ErrorHandling errorContext) { AggregateSymbol aggNullable = typeManager.GetNullable(); if (aggNullable == null) { throw Error.InternalCompilerError(); } if (ats == null) { if (aggNullable == null) { typeManager.ReportMissingPredefTypeError(errorContext, PredefinedType.PT_G_OPTIONAL); return null; } CType typePar = GetUnderlyingType(); CType[] typeParArray = new CType[] { typePar }; TypeArray ta = symmgr.AllocParams(1, typeParArray); ats = typeManager.GetAggregate(aggNullable, ta); } return ats; }
public PropWithType(PropertySymbol prop, AggregateType ats) { Set(prop, ats); }
public virtual void Clear() { _sym = null; _ats = null; }
public MethPropWithInst(MethodOrPropertySymbol mps, AggregateType ats, TypeArray typeArgs) { Set(mps, ats, typeArgs); }
public FieldWithType(FieldSymbol field, AggregateType ats) { Set(field, ats); }
public MethWithInst(MethodSymbol meth, AggregateType ats) : this(meth, ats, null) { }
public MethWithType(MethodSymbol meth, AggregateType ats) { Set(meth, ats); }
public SubstContext(AggregateType type, TypeArray typeArgsMeth) : this(type, typeArgsMeth, SubstTypeFlags.NormNone) { }
private static bool IsDelegateType(CType pSrcType, AggregateType pAggType) => TypeManager.SubstType(pSrcType, pAggType, pAggType.TypeArgsAll).IsDelegateType;
public SubstContext(AggregateType type) : this(type, null, SubstTypeFlags.NormNone) { }
private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc) { AggregateSymbol aggSrc = aggTypeSrc.getAggregate(); Debug.Assert(aggSrc.getThisType().isSimpleType()); Debug.Assert(_typeDest.isSimpleType()); Debug.Assert(aggSrc.IsPredefined() && _typeDest.isPredefined()); PredefinedType ptSrc = aggSrc.GetPredefType(); PredefinedType ptDest = _typeDest.getPredefType(); ConvKind convertKind; bool fConstShrinkCast = false; Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES); // 13.1.7 Implicit constant expression conversions // // An implicit constant expression conversion permits the following conversions: // * A constant-expression (14.16) of type int can be converted to type sbyte, byte, short, // ushort, uint, or ulong, provided the value of the constant-expression is within the range // of the destination type. // * A constant-expression of type long can be converted to type ulong, provided the value of // the constant-expression is not negative. // Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants. if (_exprSrc != null && _exprSrc.isCONSTANT_OK() && ((ptSrc == PredefinedType.PT_INT && ptDest != PredefinedType.PT_BOOL && ptDest != PredefinedType.PT_CHAR) || (ptSrc == PredefinedType.PT_LONG && ptDest == PredefinedType.PT_ULONG)) && isConstantInRange(_exprSrc.asCONSTANT(), _typeDest)) { // Special case (CLR 6.1.6): if integral constant is in range, the conversion is a legal implicit conversion. convertKind = ConvKind.Implicit; fConstShrinkCast = _needsExprDest && (GetConvKind(ptSrc, ptDest) != ConvKind.Implicit); } else if (ptSrc == ptDest) { // Special case: precision limiting casts to float or double Debug.Assert(ptSrc == PredefinedType.PT_FLOAT || ptSrc == PredefinedType.PT_DOUBLE); Debug.Assert(0 != (_flags & CONVERTTYPE.ISEXPLICIT)); convertKind = ConvKind.Implicit; } else { convertKind = GetConvKind(ptSrc, ptDest); Debug.Assert(convertKind != ConvKind.Identity); // identity conversion should have been handled at first. } if (convertKind != ConvKind.Implicit) { return(false); } // An implicit conversion exists. Do the conversion. if (_exprSrc.GetConst() != null) { // Fold the constant cast if possible. ConstCastResult result = _binder.bindConstantCast(_exprSrc, _exprTypeDest, _needsExprDest, out _exprDest, false); if (result == ConstCastResult.Success) { return(true); // else, don't fold and use a regular cast, below. } } if (isUserDefinedConversion(ptSrc, ptDest)) { if (!_needsExprDest) { return(true); } // According the language, this is a standard conversion, but it is implemented // through a user-defined conversion. Because it's a standard conversion, we don't // test the NOUDC flag here. return(_binder.bindUserDefinedConversion(_exprSrc, aggTypeSrc, _typeDest, _needsExprDest, out _exprDest, true)); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest); } return(true); }
public void InsertAggregate( AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType pAggregate) { Debug.Assert(LookupAggregate(aggregate, outer, args) == null); _aggregateTable.Add(MakeKey(aggregate, MakeKey(outer, args)), pAggregate); }
public AggregateType LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args) { _aggregateTable.TryGetValue(MakeKey(aggregate, MakeKey(outer, args)), out AggregateType result); return(result); }
public MethPropWithType(MethodOrPropertySymbol mps, AggregateType ats) { Set(mps, ats); }
private SubstContext(AggregateType type, TypeArray typeArgsMeth, SubstTypeFlags grfst) { Init(type != null ? type.GetTypeArgsAll() : null, typeArgsMeth, grfst); }
/*************************************************************************************************** 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) { ExprUserDefinedConversion exprUDC = exprTmp as ExprUserDefinedConversion; 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++) { ExprCall call = _binder.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, 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); ExprMemberGroup 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.NullableCallLiftKind = NullableCallLiftKind.NullableConversion; exprDst.PConversions = exprDst.CastOfNonLiftedResultToLiftedType; _exprDest = exprDst; } return true; }
//////////////////////////////////////////////////////////////////////////////// private bool LowerBoundInterfaceInference(CType pSource, AggregateType pDest) { if (!pDest.isInterfaceType()) { return false; } // SPEC: Otherwise, if V is an interface CType C<V1...Vk> and U is a class CType // SPEC: or struct CType and there is a unique set U1...Uk such that U directly // SPEC: or indirectly implements C<U1...Uk> then an // SPEC: exact, upper-bound, or lower-bound inference ... // SPEC: ... and U is an interface CType ... // SPEC: ... and U is a CType parameter ... //TypeArray pInterfaces = null; if (!pSource.isStructType() && !pSource.isClassType() && !pSource.isInterfaceType() && !pSource.IsTypeParameterType()) { return false; } var interfaces = pSource.AllPossibleInterfaces(); AggregateType pInterface = null; foreach (AggregateType pCurrent in interfaces) { if (pCurrent.GetOwningAggregate() == pDest.GetOwningAggregate()) { if (pInterface == null) { pInterface = pCurrent; } else if (pInterface != pCurrent) { // Not unique. Bail out. return false; } } } if (pInterface == null) { return false; } LowerBoundTypeArgumentInference(pInterface, pDest); return true; }
public SymWithType(Symbol sym, AggregateType ats) { Set(sym, ats); }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundInterfaceInference(AggregateType pSource, CType pDest) { if (!pSource.isInterfaceType()) { return false; } // SPEC: Otherwise, if U is an interface CType C<U1...Uk> and V is a class CType // SPEC: or struct CType and there is a unique set V1...Vk such that V directly // SPEC: or indirectly implements C<V1...Vk> then an exact ... // SPEC: ... and U is an interface CType ... if (!pDest.isStructType() && !pDest.isClassType() && !pDest.isInterfaceType()) { return false; } var interfaces = pDest.AllPossibleInterfaces(); AggregateType pInterface = null; foreach (AggregateType pCurrent in interfaces) { if (pCurrent.GetOwningAggregate() == pSource.GetOwningAggregate()) { if (pInterface == null) { pInterface = pCurrent; } else if (pInterface != pCurrent) { // Not unique. Bail out. return false; } } } if (pInterface == null) { return false; } UpperBoundTypeArgumentInference(pInterface, pDest.AsAggregateType()); return true; }
//////////////////////////////////////////////////////////////////////////////// private TypeArray GetFixedDelegateParameters(AggregateType pDelegateType) { Debug.Assert(pDelegateType.isDelegateType()); // We have a delegate where the input types use no unfixed parameters. Create // a substitution context; we can substitute unfixed parameters for themselves // since they don't actually occur in the inputs. (They may occur in the outputs, // or there may be input parameters fixed to _unfixed_ method CType variables. // Both of those scenarios are legal.) CType[] ppMethodParameters = new CType[_pMethodTypeParameters.size]; for (int iParam = 0; iParam < _pMethodTypeParameters.size; iParam++) { TypeParameterType pParam = _pMethodTypeParameters.ItemAsTypeParameterType(iParam); ppMethodParameters[iParam] = IsUnfixed(iParam) ? pParam : _pFixedResults[iParam]; } SubstContext subsctx = new SubstContext(_pClassTypeArguments.ToArray(), _pClassTypeArguments.size, ppMethodParameters, _pMethodTypeParameters.size); AggregateType pFixedDelegateType = GetTypeManager().SubstType(pDelegateType, subsctx).AsAggregateType(); TypeArray pFixedDelegateParams = pFixedDelegateType.GetDelegateParameters(GetSymbolLoader()); return pFixedDelegateParams; }
public MethPropWithInst(MethodOrPropertySymbol mps, AggregateType ats) : this(mps, ats, null) { }
public MethWithInst(MethodSymbol meth, AggregateType ats, TypeArray typeArgs) { Set(meth, ats, typeArgs); }
public EventWithType(EventSymbol @event, AggregateType ats) { Set(@event, ats); }
protected virtual EXPRARRINIT GenerateMembersArray(AggregateType anonymousType, PredefinedType pt) { EXPR newArgs = null; EXPR newArgsTail = newArgs; int methodCount = 0; AggregateSymbol aggSym = anonymousType.getAggregate(); for (Symbol member = aggSym.firstChild; member != null; member = member.nextChild) { if (member.IsMethodSymbol()) { MethodSymbol method = member.AsMethodSymbol(); if (method.MethKind() == MethodKindEnum.PropAccessor) { EXPRMETHODINFO methodInfo = GetExprFactory().CreateMethodInfo(method, anonymousType, method.Params); GetExprFactory().AppendItemToList(methodInfo, ref newArgs, ref newArgsTail); methodCount++; } } } AggregateType paramsArrayElementType = GetSymbolLoader().GetOptPredefTypeErr(pt, true); ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1); EXPRCONSTANT paramsArrayArg = GetExprFactory().CreateIntegerConstant(methodCount); EXPRARRINIT arrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, paramsArrayType, newArgs, paramsArrayArg, null); arrayInit.dimSize = methodCount; arrayInit.dimSizes = new int[] { arrayInit.dimSize }; // CLEANUP: Why isn't this done by the factory? return arrayInit; }
// // SymbolLoader forwarders (end) ///////////////////////////////////////////////////////////////////////////////// // // Utility methods // private ACCESSERROR CheckAccessCore(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { Debug.Assert(symCheck != null); Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate()); Debug.Assert(typeThru == null || typeThru.IsAggregateType() || typeThru.IsTypeParameterType() || typeThru.IsArrayType() || typeThru.IsNullableType() || typeThru.IsErrorType()); switch (symCheck.GetAccess()) { default: throw Error.InternalCompilerError(); //return ACCESSERROR.ACCESSERROR_NOACCESS; case ACCESS.ACC_UNKNOWN: return(ACCESSERROR.ACCESSERROR_NOACCESS); case ACCESS.ACC_PUBLIC: return(ACCESSERROR.ACCESSERROR_NOERROR); case ACCESS.ACC_PRIVATE: case ACCESS.ACC_PROTECTED: if (symWhere == null) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } break; case ACCESS.ACC_INTERNAL: case ACCESS.ACC_INTERNALPROTECTED: // Check internal, then protected. if (symWhere == null) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } if (symWhere.SameAssemOrFriend(symCheck)) { return(ACCESSERROR.ACCESSERROR_NOERROR); } if (symCheck.GetAccess() == ACCESS.ACC_INTERNAL) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } break; } // Should always have atsCheck for private and protected access check. // We currently don't need it since access doesn't respect instantiation. // We just use symWhere.parent.AsAggregateSymbol() instead. AggregateSymbol aggCheck = symCheck.parent.AsAggregateSymbol(); // Find the inner-most enclosing AggregateSymbol. AggregateSymbol aggWhere = null; for (Symbol symT = symWhere; symT != null; symT = symT.parent) { if (symT.IsAggregateSymbol()) { aggWhere = symT.AsAggregateSymbol(); break; } if (symT.IsAggregateDeclaration()) { aggWhere = symT.AsAggregateDeclaration().Agg(); break; } } if (aggWhere == null) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } // First check for private access. for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { if (agg == aggCheck) { return(ACCESSERROR.ACCESSERROR_NOERROR); } } if (symCheck.GetAccess() == ACCESS.ACC_PRIVATE) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } // Handle the protected case - which is the only real complicated one. Debug.Assert(symCheck.GetAccess() == ACCESS.ACC_PROTECTED || symCheck.GetAccess() == ACCESS.ACC_INTERNALPROTECTED); // Check if symCheck is in aggWhere or a base of aggWhere, // or in an outer agg of aggWhere or a base of an outer agg of aggWhere. AggregateType atsThru = null; if (typeThru != null && !symCheck.isStatic) { atsThru = SymbolLoader.GetAggTypeSym(typeThru); } // Look for aggCheck among the base classes of aggWhere and outer aggs. bool found = false; for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { Debug.Assert(agg != aggCheck); // We checked for this above. // Look for aggCheck among the base classes of agg. if (agg.FindBaseAgg(aggCheck)) { found = true; // aggCheck is a base class of agg. Check atsThru. // For non-static protected access to be legal, atsThru must be an instantiation of // agg or a CType derived from an instantiation of agg. In this case // all that matters is that agg is in the base AggregateSymbol chain of atsThru. The // actual AGGTYPESYMs involved don't matter. if (atsThru == null || atsThru.getAggregate().FindBaseAgg(agg)) { return(ACCESSERROR.ACCESSERROR_NOERROR); } } } // the CType in which the method is being called has no relationship with the // CType on which the method is defined surely this is NOACCESS and not NOACCESSTHRU if (found == false) { return(ACCESSERROR.ACCESSERROR_NOACCESS); } return((atsThru == null) ? ACCESSERROR.ACCESSERROR_NOACCESS : ACCESSERROR.ACCESSERROR_NOACCESSTHRU); }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundClassInference(AggregateType pSource, CType pDest) { if (!pSource.isClassType() || !pDest.isClassType()) { return false; } // SPEC: Otherwise, if U is a class CType C<U1...Uk> and V is a class CType which // SPEC: inherits directly or indirectly from C<V1...Vk> then an exact // SPEC: inference is made from each Ui to the corresponding Vi. AggregateType pDestBase = pDest.AsAggregateType().GetBaseClass(); while (pDestBase != null) { if (pDestBase.GetOwningAggregate() == pSource.GetOwningAggregate()) { ExactTypeArgumentInference(pSource, pDestBase); return true; } pDestBase = pDestBase.GetBaseClass(); } return false; }
public bool CheckAccess(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { return(CheckAccess2(symCheck, atsCheck, symWhere, typeThru) == ACCESSERROR.ACCESSERROR_NOERROR); }
//////////////////////////////////////////////////////////////////////////////// private void UpperBoundTypeArgumentInference( AggregateType pSource, AggregateType pDest) { // SPEC: The choice of inference for the i-th CType argument is made // SPEC: based on the declaration of the i-th CType parameter of C, as // SPEC: follows: // SPEC: if Ui is known to be of reference CType and the i-th CType parameter // SPEC: was declared as covariant then an upper-bound inference is made. // SPEC: if Ui is known to be of reference CType and the i-th CType parameter // SPEC: was declared as contravariant then a lower-bound inference is made. // SPEC: otherwise, an exact inference is made. Debug.Assert(pSource != null); Debug.Assert(pDest != null); Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate()); TypeArray pTypeParams = pSource.GetOwningAggregate().GetTypeVarsAll(); TypeArray pSourceArgs = pSource.GetTypeArgsAll(); TypeArray pDestArgs = pDest.GetTypeArgsAll(); Debug.Assert(pTypeParams != null); Debug.Assert(pSourceArgs != null); Debug.Assert(pDestArgs != null); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pDestArgs.size); for (int arg = 0; arg < pSourceArgs.size; ++arg) { TypeParameterType pTypeParam = pTypeParams.ItemAsTypeParameterType(arg); CType pSourceArg = pSourceArgs.Item(arg); CType pDestArg = pDestArgs.Item(arg); if (pSourceArg.IsRefType() && pTypeParam.Covariant) { UpperBoundInference(pSourceArg, pDestArg); } else if (pSourceArg.IsRefType() && pTypeParam.Contravariant) { LowerBoundInference(pSourceArgs.Item(arg), pDestArgs.Item(arg)); } else { ExactInference(pSourceArgs.Item(arg), pDestArgs.Item(arg)); } } }
////////////////////////////////////////////////////////////////////////////// private bool HasDelegateConversion(AggregateType pSource, AggregateType pDest) { Debug.Assert(pSource != null && pSource.isDelegateType()); Debug.Assert(pDest != null && pDest.isDelegateType()); return(HasVariantConversion(pSource, pDest)); }
// // SymbolLoader forwarders (end) ///////////////////////////////////////////////////////////////////////////////// // // Utility methods // protected ACCESSERROR CheckAccessCore(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { Debug.Assert(symCheck != null); Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate()); Debug.Assert(typeThru == null || typeThru.IsAggregateType() || typeThru.IsTypeParameterType() || typeThru.IsArrayType() || typeThru.IsNullableType() || typeThru.IsErrorType()); switch (symCheck.GetAccess()) { default: throw Error.InternalCompilerError(); //return ACCESSERROR.ACCESSERROR_NOACCESS; case ACCESS.ACC_UNKNOWN: return ACCESSERROR.ACCESSERROR_NOACCESS; case ACCESS.ACC_PUBLIC: return ACCESSERROR.ACCESSERROR_NOERROR; case ACCESS.ACC_PRIVATE: case ACCESS.ACC_PROTECTED: if (symWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } break; case ACCESS.ACC_INTERNAL: case ACCESS.ACC_INTERNALPROTECTED: // Check internal, then protected. if (symWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } if (symWhere.SameAssemOrFriend(symCheck)) { return ACCESSERROR.ACCESSERROR_NOERROR; } if (symCheck.GetAccess() == ACCESS.ACC_INTERNAL) { return ACCESSERROR.ACCESSERROR_NOACCESS; } break; } // Should always have atsCheck for private and protected access check. // We currently don't need it since access doesn't respect instantiation. // We just use symWhere.parent.AsAggregateSymbol() instead. AggregateSymbol aggCheck = symCheck.parent.AsAggregateSymbol(); // Find the inner-most enclosing AggregateSymbol. AggregateSymbol aggWhere = null; for (Symbol symT = symWhere; symT != null; symT = symT.parent) { if (symT.IsAggregateSymbol()) { aggWhere = symT.AsAggregateSymbol(); break; } if (symT.IsAggregateDeclaration()) { aggWhere = symT.AsAggregateDeclaration().Agg(); break; } } if (aggWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } // First check for private access. for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { if (agg == aggCheck) { return ACCESSERROR.ACCESSERROR_NOERROR; } } if (symCheck.GetAccess() == ACCESS.ACC_PRIVATE) { return ACCESSERROR.ACCESSERROR_NOACCESS; } // Handle the protected case - which is the only real complicated one. Debug.Assert(symCheck.GetAccess() == ACCESS.ACC_PROTECTED || symCheck.GetAccess() == ACCESS.ACC_INTERNALPROTECTED); // Check if symCheck is in aggWhere or a base of aggWhere, // or in an outer agg of aggWhere or a base of an outer agg of aggWhere. AggregateType atsThru = null; if (typeThru != null && !symCheck.isStatic) { atsThru = SymbolLoader.GetAggTypeSym(typeThru); } // Look for aggCheck among the base classes of aggWhere and outer aggs. bool found = false; for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { Debug.Assert(agg != aggCheck); // We checked for this above. // Look for aggCheck among the base classes of agg. if (agg.FindBaseAgg(aggCheck)) { found = true; // aggCheck is a base class of agg. Check atsThru. // For non-static protected access to be legal, atsThru must be an instantiation of // agg or a CType derived from an instantiation of agg. In this case // all that matters is that agg is in the base AggregateSymbol chain of atsThru. The // actual AGGTYPESYMs involved don't matter. if (atsThru == null || atsThru.getAggregate().FindBaseAgg(agg)) { return ACCESSERROR.ACCESSERROR_NOERROR; } } } // the CType in which the method is being called has no relationship with the // CType on which the method is defined surely this is NOACCESS and not NOACCESSTHRU if (found == false) return ACCESSERROR.ACCESSERROR_NOACCESS; return (atsThru == null) ? ACCESSERROR.ACCESSERROR_NOACCESS : ACCESSERROR.ACCESSERROR_NOACCESSTHRU; }
// Check the constraints of any type arguments in the given Type. public static bool CheckConstraints(CSemanticChecker checker, ErrorHandling errHandling, CType type, CheckConstraintsFlags flags) { type = type.GetNakedType(false); if (type.IsNullableType()) { CType typeT = type.AsNullableType().GetAts(checker.GetErrorContext()); if (typeT != null) { type = typeT; } else { type = type.GetNakedType(true); } } if (!type.IsAggregateType()) { return(true); } AggregateType ats = type.AsAggregateType(); if (ats.GetTypeArgsAll().size == 0) { // Common case: there are no type vars, so there are no constraints. ats.fConstraintsChecked = true; ats.fConstraintError = false; return(true); } if (ats.fConstraintsChecked) { // Already checked. if (!ats.fConstraintError || (flags & CheckConstraintsFlags.NoDupErrors) != 0) { // No errors or no need to report errors again. return(!ats.fConstraintError); } } TypeArray typeVars = ats.getAggregate().GetTypeVars(); TypeArray typeArgsThis = ats.GetTypeArgsThis(); TypeArray typeArgsAll = ats.GetTypeArgsAll(); Debug.Assert(typeVars.size == typeArgsThis.size); if (!ats.fConstraintsChecked) { ats.fConstraintsChecked = true; ats.fConstraintError = false; } // Check the outer type first. If CheckConstraintsFlags.Outer is not specified and the // outer type has already been checked then don't bother checking it. if (ats.outerType != null && ((flags & CheckConstraintsFlags.Outer) != 0 || !ats.outerType.fConstraintsChecked)) { CheckConstraints(checker, errHandling, ats.outerType, flags); ats.fConstraintError |= ats.outerType.fConstraintError; } if (typeVars.size > 0) { ats.fConstraintError |= !CheckConstraintsCore(checker, errHandling, ats.getAggregate(), typeVars, typeArgsThis, typeArgsAll, null, (flags & CheckConstraintsFlags.NoErrors)); } // Now check type args themselves. for (int i = 0; i < typeArgsThis.size; i++) { CType arg = typeArgsThis.Item(i).GetNakedType(true); if (arg.IsAggregateType() && !arg.AsAggregateType().fConstraintsChecked) { CheckConstraints(checker, errHandling, arg.AsAggregateType(), flags | CheckConstraintsFlags.Outer); if (arg.AsAggregateType().fConstraintError) { ats.fConstraintError = true; } } } return(!ats.fConstraintError); }
public bool CheckAccess(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { return CheckAccess2(symCheck, atsCheck, symWhere, typeThru) == ACCESSERROR.ACCESSERROR_NOERROR; }
/*************************************************************************************************** * Determine whether there is an explicit or implicit reference conversion (or identity conversion) * from typeSrc to typeDst. This is when: * * 13.2.3 Explicit reference conversions * * The explicit reference conversions are: * From object to any reference-type. * From any class-type S to any class-type T, provided S is a base class of T. * From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T. * From any interface-type S to any class-type T, provided T is not sealed or provided T implements S. * From any interface-type S to any interface-type T, provided S is not derived from T. * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: * o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) * o An explicit reference conversion exists from SE to TE. * From System.Array and the interfaces it implements, to any array-type. * From System.Delegate and the interfaces it implements, to any delegate-type. * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T. * From a generic delegate type S to generic delegate type T, provided all of the follow are true: * o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, * S is D<S1,... Sk> and T is D<T1,... Tk>. * o S is not compatible with or identical to T. * o If type parameter Xi is declared to be invariant then Si must be identical to Ti. * o If type parameter Xi is declared to be covariant ("out") then Si must be convertible * to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. * o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, * or Si and Ti must both be reference types. * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T. * * 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 T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. * From a type-parameter U to T provided that T depends on U (§25.7). [Note: Since T is known to be a reference type, within the scope of T, the run-time type of U will always be a reference type, even if U is not known to be a reference type at compile-time. end note] * * Both src and dst are reference types and there is a builtin explicit conversion from * src to dst. * Or src is a reference type and dst is a base type of src (in which case the conversion is * implicit as well). * Or dst is a reference type and src is a base type of dst. * * The latter two cases can happen with type variables even though the other type variable is not * a reference type. ***************************************************************************************************/ public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeDst != null); if (typeSrc.IsRefType() && typeDst.IsRefType()) { // is there an implicit reference conversion in either direction? // this handles the bulk of the cases ... if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) || loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)) { return(true); } // For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist: // • From any interface-type to T. // • From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. if (typeSrc.isInterfaceType() && typeDst is TypeParameterType) { return(true); } if (typeSrc is TypeParameterType && typeDst.isInterfaceType()) { return(true); } // * From any class-type S to any interface-type T, provided S is not sealed // * From any interface-type S to any class-type T, provided T is not sealed // * From any interface-type S to any interface-type T, provided S is not derived from T. if (typeSrc is AggregateType atSrc && typeDst is AggregateType atDst) { AggregateSymbol aggSrc = atSrc.getAggregate(); AggregateSymbol aggDest = atDst.getAggregate(); if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) || (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) || (aggSrc.IsInterface() && aggDest.IsInterface())) { return(true); } } if (typeSrc is ArrayType arrSrc) { // * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: // o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) // o An explicit reference conversion exists from SE to TE. if (typeDst is ArrayType arrDst) { return(arrSrc.rank == arrDst.rank && arrSrc.IsSZArray == arrDst.IsSZArray && FExpRefConv(loader, arrSrc.GetElementType(), arrDst.GetElementType())); } // * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> // and their base interfaces, provided there is an explicit reference conversion from S to T. if (!arrSrc.IsSZArray || !typeDst.isInterfaceType()) { return(false); } AggregateType aggDst = (AggregateType)typeDst; TypeArray typeArgsAll = aggDst.GetTypeArgsAll(); if (typeArgsAll.Count != 1) { return(false); } AggregateSymbol aggIList = loader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, aggDst.getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, aggDst.getAggregate()))) { return(false); } return(FExpRefConv(loader, arrSrc.GetElementType(), typeArgsAll[0])); } if (typeDst is ArrayType arrayDest && typeSrc is AggregateType aggtypeSrc) { // * From System.Array and the interfaces it implements, to any array-type. if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetPredefindType(PredefinedType.PT_ARRAY), typeSrc)) { return(true); } // * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a // one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to // System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T // are the same type or there is an implicit or explicit reference conversion from S to T. if (!arrayDest.IsSZArray || !typeSrc.isInterfaceType() || aggtypeSrc.GetTypeArgsAll().Count != 1) { return(false); } AggregateSymbol aggIList = loader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate()))) { return(false); } CType typeArr = arrayDest.GetElementType(); CType typeLst = aggtypeSrc.GetTypeArgsAll()[0]; Debug.Assert(!typeArr.IsNeverSameType()); return(typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst)); } if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst)) { return(true); } } else if (typeSrc.IsRefType()) { // conversion of T . U, where T : class, U // .. these constraints implies where U : class return(loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst)); } else if (typeDst.IsRefType()) { // conversion of T . U, where U : class, T // .. these constraints implies where T : class return(loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)); } return(false); }
public void Set(Symbol sym, AggregateType ats) { if (sym == null) ats = null; Debug.Assert(ats == null || sym.parent == ats.getAggregate()); _sym = sym; _ats = ats; }
/****************************************************************************** * Search just the given type (not any bases). Returns true iff it finds * something (which will have been recorded by RecordType). * * pfHideByName is set to true iff something was found that hides all * members of base types (eg, a hidebyname method). ******************************************************************************/ private bool SearchSingleType(AggregateType typeCur, out bool pfHideByName) { bool fFoundSome = false; pfHideByName = false; // Make sure this type is accessible. It may not be due to private inheritance // or friend assemblies. bool fInaccess = !GetSemanticChecker().CheckTypeAccess(typeCur, _symWhere); if (fInaccess && (_csym != 0 || _swtInaccess != null)) { return(false); } // Loop through symbols. Symbol symCur = null; for (symCur = GetSymbolLoader().LookupAggMember(_name, typeCur.getAggregate(), symbmask_t.MASK_ALL); symCur != null; symCur = GetSymbolLoader().LookupNextSym(symCur, typeCur.getAggregate(), symbmask_t.MASK_ALL)) { // Check for arity. switch (symCur.getKind()) { case SYMKIND.SK_MethodSymbol: // For non-zero arity, only methods of the correct arity are considered. // For zero arity, don't filter out any methods since we do type argument // inferencing. if (_arity > 0 && ((MethodSymbol)symCur).typeVars.Count != _arity) { if (!_swtBadArity) { _swtBadArity.Set(symCur, typeCur); } continue; } break; case SYMKIND.SK_AggregateSymbol: // For types, always filter on arity. if (((AggregateSymbol)symCur).GetTypeVars().Count != _arity) { if (!_swtBadArity) { _swtBadArity.Set(symCur, typeCur); } continue; } break; case SYMKIND.SK_TypeParameterSymbol: if ((_flags & MemLookFlags.TypeVarsAllowed) == 0) { continue; } if (_arity > 0) { if (!_swtBadArity) { _swtBadArity.Set(symCur, typeCur); } continue; } break; default: // All others are only considered when arity is zero. if (_arity > 0) { if (!_swtBadArity) { _swtBadArity.Set(symCur, typeCur); } continue; } break; } // Check for user callability. if (symCur.IsOverride() && !symCur.IsHideByName()) { if (!_swtOverride) { _swtOverride.Set(symCur, typeCur); } continue; } MethodOrPropertySymbol methProp = symCur as MethodOrPropertySymbol; MethodSymbol meth = symCur as MethodSymbol; if (methProp != null && (_flags & MemLookFlags.UserCallable) != 0 && !methProp.isUserCallable()) { // If its an indexed property method symbol, let it through. if (meth != null && meth.isPropertyAccessor() && ((symCur.name.Text.StartsWith("set_", StringComparison.Ordinal) && meth.Params.Count > 1) || (symCur.name.Text.StartsWith("get_", StringComparison.Ordinal) && meth.Params.Count > 0))) { if (!_swtInaccess) { _swtInaccess.Set(symCur, typeCur); } continue; } } if (fInaccess || !GetSemanticChecker().CheckAccess(symCur, typeCur, _symWhere, _typeQual)) { // Not accessible so get the next sym. if (!_swtInaccess) { _swtInaccess.Set(symCur, typeCur); } if (fInaccess) { return(false); } continue; } PropertySymbol prop = symCur as PropertySymbol; // Make sure that whether we're seeing a ctor, operator, or indexer is consistent with the flags. if (((_flags & MemLookFlags.Ctor) == 0) != (meth == null || !meth.IsConstructor()) || ((_flags & MemLookFlags.Operator) == 0) != (meth == null || !meth.isOperator) || ((_flags & MemLookFlags.Indexer) == 0) != !(prop is IndexerSymbol)) { if (!_swtBad) { _swtBad.Set(symCur, typeCur); } continue; } // We can't call CheckBogus on methods or indexers because if the method has the wrong // number of parameters people don't think they should have to /r the assemblies containing // the parameter types and they complain about the resulting CS0012 errors. if (!(symCur is MethodSymbol) && (_flags & MemLookFlags.Indexer) == 0 && CSemanticChecker.CheckBogus(symCur)) { // A bogus member - we can't use these, so only record them for error reporting. if (!_swtBogus) { _swtBogus.Set(symCur, typeCur); } continue; } // if we are in a calling context then we should only find a property if it is delegate valued if ((_flags & MemLookFlags.MustBeInvocable) != 0) { if ((symCur is FieldSymbol field && !IsDelegateType(field.GetType(), typeCur) && !IsDynamicMember(symCur)) || (prop != null && !IsDelegateType(prop.RetType, typeCur) && !IsDynamicMember(symCur))) { if (!_swtBad) { _swtBad.Set(symCur, typeCur); } continue; } } if (methProp != null) { MethPropWithType mwpInsert = new MethPropWithType(methProp, typeCur); _methPropWithTypeList.Add(mwpInsert); } // We have a visible symbol. fFoundSome = true; if (_swtFirst) { if (!typeCur.isInterfaceType()) { // Non-interface case. Debug.Assert(_fMulti || typeCur == _prgtype[0]); if (!_fMulti) { if (_swtFirst.Sym is FieldSymbol && symCur is EventSymbol // The isEvent bit is only set on symbols which come from source... // This is not a problem for the compiler because the field is only // accessible in the scope in which it is declared, // but in the EE we ignore accessibility... && _swtFirst.Field().isEvent ) { // m_swtFirst is just the field behind the event symCur so ignore symCur. continue; } else if (_swtFirst.Sym is FieldSymbol && symCur is EventSymbol) { // symCur is the matching event. continue; } goto LAmbig; } if (_swtFirst.Sym.getKind() != symCur.getKind()) { if (typeCur == _prgtype[0]) { goto LAmbig; } // This one is hidden by the first one. This one also hides any more in base types. pfHideByName = true; continue; } } // Interface case. // m_fMulti : n n n y y y y y // same-kind : * * * y n n n n // fDiffHidden: * * * * y n n n // meth : * * * * * y n * can n happen? just in case, we better handle it.... // hack : n * y * * y * n // meth-2 : * n y * * * * * // res : A A S R H H A A else if (!_fMulti) { // Give method groups priority. if (!(symCur is MethodSymbol)) { goto LAmbig; } _swtAmbigWarn = _swtFirst; // Erase previous results so we'll record this method as the first. _prgtype = new List <AggregateType>(); _csym = 0; _swtFirst.Clear(); _swtAmbig.Clear(); } else if (_swtFirst.Sym.getKind() != symCur.getKind()) { if (!typeCur.fDiffHidden) { // Give method groups priority. if (!(_swtFirst.Sym is MethodSymbol)) { goto LAmbig; } if (!_swtAmbigWarn) { _swtAmbigWarn.Set(symCur, typeCur); } } // This one is hidden by another. This one also hides any more in base types. pfHideByName = true; continue; } } RecordType(typeCur, symCur); if (methProp != null && methProp.isHideByName) { pfHideByName = true; } // We've found a symbol in this type but need to make sure there aren't any conflicting // syms here, so keep searching the type. } Debug.Assert(!fInaccess || !fFoundSome); return(fFoundSome); LAmbig: // Ambiguous! if (!_swtAmbig) { _swtAmbig.Set(symCur, typeCur); } pfHideByName = true; return(true); }
/****************************************************************************** * Returns true if searching should continue to object. ******************************************************************************/ private bool LookupInInterfaces(AggregateType typeStart, TypeArray types) { Debug.Assert(!_swtFirst || _fMulti); Debug.Assert(typeStart == null || typeStart.isInterfaceType()); Debug.Assert(typeStart != null || types.Count != 0); // Clear all the hidden flags. Anything found in a class hides any other // kind of member in all the interfaces. if (typeStart != null) { typeStart.fAllHidden = false; typeStart.fDiffHidden = (_swtFirst != null); } for (int i = 0; i < types.Count; i++) { AggregateType type = (AggregateType)types[i]; Debug.Assert(type.isInterfaceType()); type.fAllHidden = false; type.fDiffHidden = !!_swtFirst; } bool fHideObject = false; AggregateType typeCur = typeStart; int itypeNext = 0; if (typeCur == null) { typeCur = (AggregateType)types[itypeNext++]; } Debug.Assert(typeCur != null); // Loop through the interfaces. for (; ;) { Debug.Assert(typeCur != null && typeCur.isInterfaceType()); bool fHideByName = false; if (!typeCur.fAllHidden && SearchSingleType(typeCur, out fHideByName)) { fHideByName |= !_fMulti; // Mark base interfaces appropriately. TypeArray ifaces = typeCur.GetIfacesAll(); for (int i = 0; i < ifaces.Count; i++) { AggregateType type = (AggregateType)ifaces[i]; Debug.Assert(type.isInterfaceType()); if (fHideByName) { type.fAllHidden = true; } type.fDiffHidden = true; } // If we hide all base types, that includes object! if (fHideByName) { fHideObject = true; } } _flags &= ~MemLookFlags.TypeVarsAllowed; if (itypeNext >= types.Count) { return(!fHideObject); } // Substitution has already been done. typeCur = types[itypeNext++] as AggregateType; } }
private bool IsDelegateType(CType pSrcType, AggregateType pAggType) { CType pInstantiatedType = GetSymbolLoader().GetTypeManager().SubstType(pSrcType, pAggType, pAggType.GetTypeArgsAll()); return(pInstantiatedType.isDelegateType()); }
/*************************************************************************************************** * 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 is AggregateType || typeSrc is TypeParameterType); Debug.Assert(checker != null); _prgtype = _rgtypeStart; // Save the inputs for error handling, etc. _pSemanticChecker = checker; _pSymbolLoader = checker.SymbolLoader; _typeSrc = typeSrc; _obj = obj is ExprClass ? null : obj; _symWhere = symWhere; _name = name; _arity = arity; _flags = flags; _typeQual = (_flags & MemLookFlags.Ctor) != 0 ? _typeSrc : obj?.Type; // Determine what to search. AggregateType typeCls1 = null; AggregateType typeIface = null; TypeArray ifaces = BSYMMGR.EmptyTypeArray(); AggregateType typeCls2 = null; if (typeSrc is TypeParameterType typeParamSrc) { Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall | MemLookFlags.TypeVarsAllowed)) == 0); _flags &= ~MemLookFlags.TypeVarsAllowed; ifaces = typeParamSrc.GetInterfaceBounds(); typeCls1 = typeParamSrc.GetEffectiveBaseClass(); if (ifaces.Count > 0 && typeCls1.isPredefType(PredefinedType.PT_OBJECT)) { typeCls1 = null; } } else if (!typeSrc.isInterfaceType()) { typeCls1 = (AggregateType)typeSrc; 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 = (AggregateType)typeSrc; ifaces = typeIface.GetIfacesAll(); } if (typeIface != null || ifaces.Count > 0) { typeCls2 = GetSymbolLoader().GetPredefindType(PredefinedType.PT_OBJECT); } // Search the class first (except possibly object). if (typeCls1 == null || LookupInClass(typeCls1, ref typeCls2)) { // Search the interfaces. if ((typeIface != null || ifaces.Count > 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()); }
public void Set(MethodOrPropertySymbol mps, AggregateType ats, TypeArray typeArgs) { if (mps == null) { ats = null; typeArgs = null; } Debug.Assert(ats == null || mps != null && mps.getClass() == ats.getAggregate()); base.Set(mps, ats); this.TypeArgs = typeArgs; }
public void SetBaseClass(AggregateType baseClass) { _pBaseClass = baseClass; }
public void SetUnderlyingType(AggregateType underlyingType) { _pUnderlyingType = underlyingType; }
private AggCastResult bindExplicitConversionBetweenSimpleTypes(AggregateType aggTypeDest) { // 13.2.1 // // Because the explicit conversions include all implicit and explicit numeric conversions, // it is always possible to convert from any numeric-type to any other numeric-type using // a cast expression (14.6.6). Debug.Assert(_typeSrc != null); Debug.Assert(aggTypeDest != null); if (!_typeSrc.IsSimpleType || !aggTypeDest.IsSimpleType) { return(AggCastResult.Failure); } AggregateSymbol aggDest = aggTypeDest.OwningAggregate; Debug.Assert(_typeSrc.IsPredefined && aggDest.IsPredefined()); PredefinedType ptSrc = _typeSrc.PredefinedType; PredefinedType ptDest = aggDest.GetPredefType(); Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES); ConvKind convertKind = GetConvKind(ptSrc, ptDest); // Identity and implicit conversions should already have been handled. Debug.Assert(convertKind != ConvKind.Implicit); Debug.Assert(convertKind != ConvKind.Identity); if (convertKind != ConvKind.Explicit) { return(AggCastResult.Failure); } if (_exprSrc.GetConst() != null) { // Fold the constant cast if possible. ConstCastResult result = _binder.bindConstantCast(_exprSrc, _typeDest, _needsExprDest, out _exprDest, true); if (result == ConstCastResult.Success) { return(AggCastResult.Success); // else, don't fold and use a regular cast, below. } if (result == ConstCastResult.CheckFailure && 0 == (_flags & CONVERTTYPE.CHECKOVERFLOW)) { return(AggCastResult.Abort); } } bool bConversionOk = true; if (_needsExprDest) { // Explicit conversions involving decimals are bound as user-defined conversions. if (isUserDefinedConversion(ptSrc, ptDest)) { // According the language, this is a standard conversion, but it is implemented // through a user-defined conversion. Because it's a standard conversion, we don't // test the CONVERTTYPE.NOUDC flag here. bConversionOk = _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, aggTypeDest, _needsExprDest, out _exprDest, false); } else { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, (_flags & CONVERTTYPE.CHECKOVERFLOW) != 0 ? EXPRFLAG.EXF_CHECKOVERFLOW : 0); } } return(bConversionOk ? AggCastResult.Success : AggCastResult.Failure); }