Exemple #1
0
 public BindingContext(CSemanticChecker semanticChecker, ExprFactory exprFactory)
 {
     Debug.Assert(semanticChecker != null);
     ExprFactory     = exprFactory;
     SemanticChecker = semanticChecker;
     SymbolLoader    = semanticChecker.SymbolLoader;
 }
Exemple #2
0
        private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, ArrayType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);

            typeDst = null;

            // We are here because we have an array type with an inaccessible element type. If possible,
            // we should create a new array type that has an accessible element type for which a
            // conversion exists.

            CType elementType = typeSrc.GetElementType();

            if (!elementType.IsRefType())
            {
                // Covariant array conversions exist for reference types only.
                return(false);
            }

            CType intermediateType;

            if (GetBestAccessibleType(semanticChecker, bindingContext, elementType, out intermediateType))
            {
                typeDst = this.GetArray(intermediateType, typeSrc.rank, typeSrc.IsSZArray);

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
                return(true);
            }

            return(false);
        }
Exemple #3
0
 public CMethodIterator GetMethodIterator(
     CSemanticChecker pChecker, SymbolLoader pSymLoader, CType pObject, CType pQualifyingType, Declaration pContext, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask)
 {
     Debug.Assert(pSymLoader != null);
     CMethodIterator iterator = new CMethodIterator(pChecker, pSymLoader, _pName, ContainingTypes, pObject, pQualifyingType, pContext, allowBogusAndInaccessible, allowExtensionMethods, arity, flags, mask);
     return iterator;
 }
Exemple #4
0
        ////////////////////////////////////////////////////////////////////////////////
        // Determine whether the arg type satisfies the typeBnd constraint. Note that
        // typeBnd could be just about any type (since we added naked type parameter
        // constraints).

        private static bool SatisfiesBound(CSemanticChecker checker, CType arg, CType typeBnd)
        {
            if (typeBnd == arg)
            {
                return(true);
            }

            switch (typeBnd.GetTypeKind())
            {
            default:
                Debug.Assert(false, "Unexpected type.");
                return(false);

            case TypeKind.TK_VoidType:
            case TypeKind.TK_PointerType:
            case TypeKind.TK_ErrorType:
                return(false);

            case TypeKind.TK_ArrayType:
            case TypeKind.TK_TypeParameterType:
                break;

            case TypeKind.TK_NullableType:
                typeBnd = typeBnd.AsNullableType().GetAts(checker.GetErrorContext());
                if (null == typeBnd)
                {
                    return(true);
                }
                break;

            case TypeKind.TK_AggregateType:
                break;
            }

            Debug.Assert(typeBnd.IsAggregateType() || typeBnd.IsTypeParameterType() || typeBnd.IsArrayType());

            switch (arg.GetTypeKind())
            {
            default:
                return(false);

            case TypeKind.TK_ErrorType:
            case TypeKind.TK_PointerType:
                return(false);

            case TypeKind.TK_NullableType:
                arg = arg.AsNullableType().GetAts(checker.GetErrorContext());
                if (null == arg)
                {
                    return(true);
                }
                // Fall through.
                goto case TypeKind.TK_TypeParameterType;

            case TypeKind.TK_TypeParameterType:
            case TypeKind.TK_ArrayType:
            case TypeKind.TK_AggregateType:
                return(checker.GetSymbolLoader().HasBaseConversion(arg, typeBnd));
            }
        }
Exemple #5
0
 public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType @object, CType qualifyingType, AggregateDeclaration 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;
     _nArity                     = arity;
     _flags                      = flags;
     _mask = mask;
     _nCurrentTypeCount          = 0;
     _bIsCheckingInstanceMethods = true;
     _bAtEnd                              = false;
     _bCurrentSymIsBogus                  = false;
     _bCurrentSymIsInaccessible           = false;
     _bcanIncludeExtensionsInResults      = allowExtensionMethods;
     _bEndIterationAtCurrentExtensionList = false;
 }
Exemple #6
0
 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;
 }
 static public BindingContext CreateInstance(
     CSemanticChecker pSemanticChecker,
     ExprFactory exprFactory,
     OutputContext outputContext,
     NameGenerator nameGenerator,
     bool bflushLocalVariableTypesForEachStatement,
     bool bAllowUnsafeBlocks,
     bool bIsOptimizingSwitchAndArrayInit,
     bool bShowReachability,
     bool bWrapNonExceptionThrows,
     bool bInRefactoring,
     KAID aidLookupContext
     )
 {
     return(new BindingContext(
                pSemanticChecker,
                exprFactory,
                outputContext,
                nameGenerator,
                bflushLocalVariableTypesForEachStatement,
                bAllowUnsafeBlocks,
                bIsOptimizingSwitchAndArrayInit,
                bShowReachability,
                bWrapNonExceptionThrows,
                bInRefactoring,
                aidLookupContext));
 }
Exemple #8
0
        private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, AggregateDeclaration context, AggregateType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeSrc.IsInterfaceType || typeSrc.IsDelegateType);

            typeDst = null;

            AggregateSymbol aggSym      = typeSrc.OwningAggregate;
            AggregateType   aggOpenType = aggSym.getThisType();

            if (!semanticChecker.CheckTypeAccess(aggOpenType, context))
            {
                // if the aggregate symbol itself is not accessible, then forget it, there is no
                // variance that will help us arrive at an accessible type.
                return(false);
            }

            TypeArray typeArgs   = typeSrc.TypeArgsThis;
            TypeArray typeParams = aggOpenType.TypeArgsThis;

            CType[] newTypeArgsTemp = new CType[typeArgs.Count];

            for (int i = 0; i < newTypeArgsTemp.Length; i++)
            {
                CType typeArg = typeArgs[i];
                if (semanticChecker.CheckTypeAccess(typeArg, context))
                {
                    // we have an accessible argument, this position is not a problem.
                    newTypeArgsTemp[i] = typeArg;
                    continue;
                }

                if (!typeArg.IsReferenceType || !((TypeParameterType)typeParams[i]).Covariant)
                {
                    // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail.
                    return(false);
                }

                newTypeArgsTemp[i] = GetBestAccessibleType(semanticChecker, context, typeArg);

                // now we either have a value type (which must be accessible due to the above
                // check, OR we have an inaccessible type (which must be a ref type). In either
                // case, the recursion worked out and we are OK to vary this argument.
            }

            TypeArray newTypeArgs      = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp);
            CType     intermediateType = GetAggregate(aggSym, typeSrc.OuterType, newTypeArgs);

            // All type arguments were varied successfully, which means now we must be accessible. But we could
            // have violated constraints. Let's check that out.

            if (!TypeBind.CheckConstraints(semanticChecker, errHandling: null, intermediateType, CheckConstraintsFlags.NoErrors))
            {
                return(false);
            }

            typeDst = intermediateType;
            Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, context));
            return(true);
        }
 static public BindingContext CreateInstance(
         CSemanticChecker pSemanticChecker,
         ExprFactory exprFactory,
         OutputContext outputContext,
         NameGenerator nameGenerator,
         bool bflushLocalVariableTypesForEachStatement,
         bool bAllowUnsafeBlocks,
         bool bIsOptimizingSwitchAndArrayInit,
         bool bShowReachability,
         bool bWrapNonExceptionThrows,
         bool bInRefactoring,
         KAID aidLookupContext
     )
 {
     return new BindingContext(
         pSemanticChecker,
         exprFactory,
         outputContext,
         nameGenerator,
         bflushLocalVariableTypesForEachStatement,
         bAllowUnsafeBlocks,
         bIsOptimizingSwitchAndArrayInit,
         bShowReachability,
         bWrapNonExceptionThrows,
         bInRefactoring,
         aidLookupContext);
 }
        protected BindingContext(
            CSemanticChecker pSemanticChecker,
            ExprFactory exprFactory,
            OutputContext outputContext,
            NameGenerator nameGenerator,
            bool bflushLocalVariableTypesForEachStatement,
            bool bAllowUnsafeBlocks,
            bool bIsOptimizingSwitchAndArrayInit,
            bool bShowReachability,
            bool bWrapNonExceptionThrows,
            bool bInRefactoring,
            KAID aidLookupContext
            )
        {
            m_ExprFactory            = exprFactory;
            m_outputContext          = outputContext;
            m_pNameGenerator         = nameGenerator;
            m_pInputFile             = null;
            m_pParentDecl            = null;
            m_pContainingAgg         = null;
            m_pCurrentSwitchType     = null;
            m_pOriginalConstantField = null;
            m_pCurrentFieldSymbol    = null;
            m_pImplicitlyTypedLocal  = null;
            m_pOuterScope            = null;
            m_pFinallyScope          = null;
            m_pTryScope                                = null;
            m_pCatchScope                              = null;
            m_pCurrentScope                            = null;
            m_pSwitchScope                             = null;
            m_pCurrentBlock                            = null;
            m_UnsafeState                              = UNSAFESTATES.UNSAFESTATES_Unknown;
            m_FinallyNestingCount                      = 0;
            m_bInsideTryOfCatch                        = false;
            m_bInFieldInitializer                      = false;
            m_bInBaseConstructorCall                   = false;
            m_bAllowUnsafeBlocks                       = bAllowUnsafeBlocks;
            m_bIsOptimizingSwitchAndArrayInit          = bIsOptimizingSwitchAndArrayInit;
            m_bShowReachability                        = bShowReachability;
            m_bWrapNonExceptionThrows                  = bWrapNonExceptionThrows;
            m_bInRefactoring                           = bInRefactoring;
            m_bInAttribute                             = false;
            m_bRespectSemanticsAndReportErrors         = true;
            m_bflushLocalVariableTypesForEachStatement = bflushLocalVariableTypesForEachStatement;
            m_ppamis          = null;
            m_pamiCurrent     = null;
            m_pInitType       = null;
            m_returnErrorSink = null;

            Debug.Assert(pSemanticChecker != null);
            this.SemanticChecker                   = pSemanticChecker;
            this.SymbolLoader                      = SemanticChecker.GetSymbolLoader();
            m_outputContext.m_pThisPointer         = null;
            m_outputContext.m_pCurrentMethodSymbol = null;

            m_aidExternAliasLookupContext = aidLookupContext;
            CheckedNormal   = false;
            CheckedConstant = false;
        }
        protected BindingContext(
            CSemanticChecker pSemanticChecker,
            ExprFactory exprFactory,
            OutputContext outputContext,
            NameGenerator nameGenerator,
            bool bflushLocalVariableTypesForEachStatement,
            bool bAllowUnsafeBlocks,
            bool bIsOptimizingSwitchAndArrayInit,
            bool bShowReachability,
            bool bWrapNonExceptionThrows,
            bool bInRefactoring,
            KAID aidLookupContext
            )
        {
            m_ExprFactory = exprFactory;
            m_outputContext = outputContext;
            m_pNameGenerator = nameGenerator;
            m_pInputFile = null;
            m_pParentDecl = null;
            m_pContainingAgg = null;
            m_pCurrentSwitchType = null;
            m_pOriginalConstantField = null;
            m_pCurrentFieldSymbol = null;
            m_pImplicitlyTypedLocal = null;
            m_pOuterScope = null;
            m_pFinallyScope = null;
            m_pTryScope = null;
            m_pCatchScope = null;
            m_pCurrentScope = null;
            m_pSwitchScope = null;
            m_pCurrentBlock = null;
            m_UnsafeState = UNSAFESTATES.UNSAFESTATES_Unknown;
            m_FinallyNestingCount = 0;
            m_bInsideTryOfCatch = false;
            m_bInFieldInitializer = false;
            m_bInBaseConstructorCall = false;
            m_bAllowUnsafeBlocks = bAllowUnsafeBlocks;
            m_bIsOptimizingSwitchAndArrayInit = bIsOptimizingSwitchAndArrayInit;
            m_bShowReachability = bShowReachability;
            m_bWrapNonExceptionThrows = bWrapNonExceptionThrows;
            m_bInRefactoring = bInRefactoring;
            m_bInAttribute = false;
            m_bRespectSemanticsAndReportErrors = true;
            m_bflushLocalVariableTypesForEachStatement = bflushLocalVariableTypesForEachStatement;
            m_ppamis = null;
            m_pamiCurrent = null;
            m_pInitType = null;
            m_returnErrorSink = null;

            Debug.Assert(pSemanticChecker != null);
            this.SemanticChecker = pSemanticChecker;
            this.SymbolLoader = SemanticChecker.GetSymbolLoader();
            m_outputContext.m_pThisPointer = null;
            m_outputContext.m_pCurrentMethodSymbol = null;

            m_aidExternAliasLookupContext = aidLookupContext;
            CheckedNormal = false;
            CheckedConstant = false;
        }
        public CMethodIterator GetMethodIterator(
            CSemanticChecker pChecker, SymbolLoader pSymLoader, CType pQualifyingType, AggregateDeclaration pContext, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments)
        {
            Debug.Assert(pSymLoader != null);
            CMethodIterator iterator = new CMethodIterator(pChecker, pSymLoader, _pName, ContainingTypes, pQualifyingType, pContext, arity, flags, mask, nonTrailingNamedArguments);

            return(iterator);
        }
Exemple #13
0
        public CMethodIterator GetMethodIterator(
            CSemanticChecker pChecker, SymbolLoader pSymLoader, CType pObject, CType pQualifyingType, Declaration pContext, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask)
        {
            Debug.Assert(pSymLoader != null);
            CMethodIterator iterator = new CMethodIterator(pChecker, pSymLoader, _pName, ContainingTypes, pObject, pQualifyingType, pContext, allowBogusAndInaccessible, allowExtensionMethods, arity, flags, mask);

            return(iterator);
        }
Exemple #14
0
        ////////////////////////////////////////////////////////////////////////////////
        // Check the constraints on the method instantiation.
        public static void CheckMethConstraints(CSemanticChecker checker, ErrorHandling errCtx, MethWithInst mwi)
        {
            Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null);
            Debug.Assert(mwi.Meth().typeVars.Count == mwi.TypeArgs.Count);
            Debug.Assert(mwi.GetType().getAggregate() == mwi.Meth().getClass());

            if (mwi.TypeArgs.Count > 0)
            {
                CheckConstraintsCore(checker, errCtx, mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().GetTypeArgsAll(), mwi.TypeArgs, CheckConstraintsFlags.None);
            }
        }
Exemple #15
0
        private static RuntimeBinderException ReportBogus(SymWithType swt)
        {
            Debug.Assert(CSemanticChecker.CheckBogus(swt.Sym));
            MethodSymbol meth1 = swt.Prop().GetterMethod;
            MethodSymbol meth2 = swt.Prop().SetterMethod;

            Debug.Assert((meth1 ?? meth2) != null);
            return(meth1 == null | meth2 == null
                ? ErrorHandling.Error(
                       ErrorCode.ERR_BindToBogusProp1, swt.Sym.name, new SymWithType(meth1 ?? meth2, swt.GetType()),
                       new ErrArgRefOnly(swt.Sym))
                : ErrorHandling.Error(
                       ErrorCode.ERR_BindToBogusProp2, swt.Sym.name, new SymWithType(meth1, swt.GetType()),
                       new SymWithType(meth2, swt.GetType()), new ErrArgRefOnly(swt.Sym)));
        }
 public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType qualifyingType, AggregateDeclaration context, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments)
 {
     Debug.Assert(name != null);
     Debug.Assert(symLoader != null);
     Debug.Assert(checker != null);
     Debug.Assert(containingTypes != null);
     Debug.Assert(containingTypes.Count != 0);
     _semanticChecker           = checker;
     _symbolLoader              = symLoader;
     _name                      = name;
     _containingTypes           = containingTypes;
     _qualifyingType            = qualifyingType;
     _context                   = context;
     _arity                     = arity;
     _flags                     = flags;
     _mask                      = mask;
     _nonTrailingNamedArguments = nonTrailingNamedArguments;
 }
Exemple #17
0
        private void Reset()
        {
            _controller = new RuntimeBinderController();
            _semanticChecker = new LangCompiler(_controller, new NameManager());

            BSYMMGR bsymmgr = _semanticChecker.getBSymmgr();
            NameManager nameManager = _semanticChecker.GetNameManager();

            InputFile infile = bsymmgr.GetMiscSymFactory().CreateMDInfile(nameManager.Lookup(""), (mdToken)0);
            infile.SetAssemblyID(bsymmgr.AidAlloc(infile));
            infile.AddToAlias(KAID.kaidThisAssembly);
            infile.AddToAlias(KAID.kaidGlobal);

            _symbolTable = new SymbolTable(
                bsymmgr.GetSymbolTable(),
                bsymmgr.GetSymFactory(),
                nameManager,
                _semanticChecker.GetTypeManager(),
                bsymmgr,
                _semanticChecker,
                infile);
            _semanticChecker.getPredefTypes().Init(_semanticChecker.GetErrorContext(), _symbolTable);
            _semanticChecker.GetTypeManager().InitTypeFactory(_symbolTable);
            SymbolLoader.getPredefinedMembers().RuntimeBinderSymbolTable = _symbolTable;
            SymbolLoader.SetSymbolTable(_symbolTable);

            _exprFactory = new ExprFactory(_semanticChecker.GetSymbolLoader().GetGlobalSymbolContext());
            _outputContext = new OutputContext();
            _nameGenerator = new NameGenerator();
            _bindingContext = BindingContext.CreateInstance(
                _semanticChecker,
                _exprFactory,
                _outputContext,
                _nameGenerator,
                false,
                true,
                false,
                false,
                false,
                false,
                0);
            _binder = new ExpressionBinder(_bindingContext);
        }
Exemple #18
0
        ////////////////////////////////////////////////////////////////////////////////
        // Check whether typeArgs satisfies the constraints of typeVars. The
        // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The
        // tree and symErr are used for error reporting.

        private static bool CheckConstraintsCore(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            Debug.Assert(typeVars.Count == typeArgs.Count);
            Debug.Assert(typeVars.Count > 0);
            Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors);

            bool fError = false;

            for (int i = 0; i < typeVars.Count; i++)
            {
                // Empty bounds should be set to object.
                TypeParameterType var = (TypeParameterType)typeVars[i];
                CType             arg = typeArgs[i];

                bool fOK = CheckSingleConstraint(checker, errHandling, symErr, var, arg, typeArgsCls, typeArgsMeth, flags);
                fError |= !fOK;
            }

            return(!fError);
        }
Exemple #19
0
        private void ReportBogus(SymWithType swt)
        {
            Debug.Assert(CSemanticChecker.CheckBogus(swt.Sym));
            MethodSymbol meth1 = swt.Prop().GetterMethod;
            MethodSymbol meth2 = swt.Prop().SetterMethod;

            Debug.Assert((meth1 ?? meth2) != null);
            if (meth1 == null | meth2 == null)
            {
                GetErrorContext().Error(
                    ErrorCode.ERR_BindToBogusProp1, swt.Sym.name, new SymWithType(meth1 ?? meth2, swt.GetType()),
                    new ErrArgRefOnly(swt.Sym));
            }
            else
            {
                GetErrorContext().Error(
                    ErrorCode.ERR_BindToBogusProp2, swt.Sym.name, new SymWithType(meth1, swt.GetType()),
                    new SymWithType(meth2, swt.GetType()), new ErrArgRefOnly(swt.Sym));
            }
        }
Exemple #20
0
        /////////////////////////////////////////////////////////////////////////////////

        internal SymbolTable(
            SYMTBL symTable,
            SymFactory symFactory,
            NameManager nameManager,
            TypeManager typeManager,
            BSYMMGR bsymmgr,
            CSemanticChecker semanticChecker,

            InputFile infile)
        {
            _symbolTable = symTable;
            _symFactory = symFactory;
            _nameManager = nameManager;
            _typeManager = typeManager;
            _bsymmgr = bsymmgr;
            _semanticChecker = semanticChecker;

            _infile = infile;

            ClearCache();
        }
Exemple #21
0
        private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, AggregateDeclaration context, ArrayType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);

            // We are here because we have an array type with an inaccessible element type. If possible,
            // we should create a new array type that has an accessible element type for which a
            // conversion exists.

            CType elementType = typeSrc.ElementType;

            // Covariant array conversions exist for reference types only.
            if (elementType.IsReferenceType)
            {
                CType destElement = GetBestAccessibleType(semanticChecker, context, elementType);
                typeDst = GetArray(destElement, typeSrc.Rank, typeSrc.IsSZArray);

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, context));
                return(true);
            }

            typeDst = null;
            return(false);
        }
Exemple #22
0
        private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);

            if (arg.IsOpenTypePlaceholderType())
            {
                return true;
            }

            if (arg.IsErrorType())
            {
                // Error should have been reported previously.
                return false;
            }

            if (checker.CheckBogus(arg))
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg);
                }

                return false;
            }

            if (arg.IsPointerType() || arg.isSpecialByRefType())
            {
                if (fReportErrors)
                {
                    errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg);
                }

                return false;
            }

            if (arg.isStaticClass())
            {
                if (fReportErrors)
                {
                    checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass);
                }

                return false;
            }

            bool fError = false;
            if (var.HasRefConstraint() && !arg.IsRefType())
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                }

                fError = true;
            }

            TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth);
            int itypeMin = 0;

            if (var.HasValConstraint())
            {
                // If we have a type variable that is constrained to a value type, then we
                // want to check if its a nullable type, so that we can report the 
                // constraint error below. In order to do this however, we need to check 
                // that either the type arg is not a value type, or it is a nullable type.
                //
                // To check whether or not its a nullable type, we need to get the resolved
                // bound from the type argument and check against that.

                bool bIsValueType = arg.IsValType();
                bool bIsNullable = arg.IsNullableType();
                if (bIsValueType && arg.IsTypeParameterType())
                {
                    TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds();
                    if (pArgBnds.size > 0)
                    {
                        bIsNullable = pArgBnds.Item(0).IsNullableType();
                    }
                }

                if (!bIsValueType || bIsNullable)
                {
                    if (fReportErrors)
                    {
                        errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                    }

                    fError = true;
                }

                // Since FValCon() is set it is redundant to check System.ValueType as well.
                if (bnds.size != 0 && bnds.Item(0).isPredefType(PredefinedType.PT_VALUE))
                {
                    itypeMin = 1;
                }
            }

            for (int j = itypeMin; j < bnds.size; j++)
            {
                CType typeBnd = bnds.Item(j);
                if (!SatisfiesBound(checker, arg, typeBnd))
                {
                    if (fReportErrors)
                    {
                        // The bound isn't satisfied because of a constaint type. Explain to the user why not.
                        // There are 4 main cases, based on the type of the supplied type argument:
                        //  - reference type, or type parameter known to be a reference type
                        //  - nullable type, from which there is a boxing conversion to the constraint type(see below for details)
                        //  - type varaiable
                        //  - value type
                        // These cases are broken out because: a) The sets of conversions which can be used 
                        // for constraint satisfaction is different based on the type argument supplied, 
                        // and b) Nullable is one funky type, and user's can use all the help they can get
                        // when using it.
                        ErrorCode error;
                        if (arg.IsRefType())
                        {
                            // A reference type can only satisfy bounds to types 
                            // to which they have an implicit reference conversion
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
                        }
                        else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd))    // This is inlining FBoxingConv
                        {
                            // nullable types do not satisfy bounds to every type that they are boxable to
                            // They only satisfy bounds of object and ValueType
                            if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd)
                            {
                                // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
                                // even though the conversion from Nullable to these types is a boxing conversion
                                // This is a rare case, because these bounds can never be directly stated ...
                                // These bounds can only occur when one type paramter is constrained to a second type parameter
                                // and the second type parameter is instantiated with Enum or the underlying type of the first type
                                // parameter
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
                            }
                            else
                            {
                                // Nullable types don't satisfy the bounds of any interface type
                                // even when there is a boxing conversion from the Nullable type to 
                                // the interface type. This will be a relatively common scenario
                                // so we cal it out separately from the previous case.
                                Debug.Assert(typeBnd.isInterfaceType());
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
                            }
                        }
                        else if (arg.IsTypeParameterType())
                        {
                            // Type variables can satisfy bounds through boxing and type variable conversions
                            Debug.Assert(!arg.IsRefType());
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar;
                        }
                        else
                        {
                            // Value types can only satisfy bounds through boxing conversions.
                            // Note that the exceptional case of Nullable types and boxing is handled above.
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
                        }
                        errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique));
                    }
                    fError = true;
                }
            }

            // Check the newable constraint.
            if (!var.HasNewConstraint() || arg.IsValType())
            {
                return !fError;
            }

            if (arg.isClassType())
            {
                AggregateSymbol agg = arg.AsAggregateType().getAggregate();

                // Due to late binding nature of IDE created symbols, the AggregateSymbol might not
                // have all the information necessary yet, if it is not fully bound.
                // by calling LookupAggMember, it will ensure that we will update all the
                // information necessary at least for the given method.
                checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL);

                if (agg.HasPubNoArgCtor() && !agg.IsAbstract())
                {
                    return !fError;
                }
            }
            else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint())
            {
                return !fError;
            }

            if (fReportErrors)
            {
                errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
            }

            return false;
        }
Exemple #23
0
        // 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;
        }
Exemple #24
0
        /***************************************************************************************************
        *   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);
            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.IsInterfaceType)
            {
                typeCls1 = (AggregateType)typeSrc;

                if (typeCls1.IsWindowsRuntimeType)
                {
                    ifaces = typeCls1.GetWinRTCollectionIfacesAll(GetSymbolLoader());
                }
            }
            else
            {
                Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0);
                typeIface = (AggregateType)typeSrc;
                ifaces    = typeIface.IfacesAll;
            }

            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);
                }
            }

            return(!FError());
        }
Exemple #25
0
            /*
             * 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 is MethodGroupType)
                {
                    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.TypeKind)
                {
                case TypeKind.TK_NullType:
                    // Can only convert to the null type if src is null.
                    if (!(_typeSrc is NullType))
                    {
                        return(false);
                    }
                    if (_needsExprDest)
                    {
                        _exprDest = _exprSrc;
                    }
                    return(true);

                case TypeKind.TK_ArgumentListType:
                    return(_typeSrc == _typeDest);

                case TypeKind.TK_VoidType:
                    return(false);

                default:
                    break;
                }

                // 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 is NullableType nubDest)
                {
                    return(BindNubConversion(nubDest));
                }

                if (_typeSrc is NullableType nubSrc)
                {
                    return(bindImplicitConversionFromNullable(nubSrc));
                }

                if ((_flags & CONVERTTYPE.ISEXPLICIT) != 0)
                {
                    _flags |= CONVERTTYPE.NOUDC;
                }

                // Get the fundamental types of destination.
                FUNDTYPE ftDest = _typeDest.FundamentalType;

                Debug.Assert(ftDest != FUNDTYPE.FT_NONE || _typeDest is ParameterModifierType);

                switch (_typeSrc.TypeKind)
                {
                default:
                    Debug.Fail($"Bad type symbol kind: {_typeSrc.TypeKind}");
                    break;

                case TypeKind.TK_VoidType:
                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_AggregateType:
                    if (bindImplicitConversionFromAgg(_typeSrc as AggregateType))
                    {
                        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.
                object srcRuntimeObject = _exprSrc?.RuntimeObject;

                if (srcRuntimeObject != null &&
                    _typeDest.AssociatedSystemType.IsInstanceOfType(srcRuntimeObject) &&
                    CSemanticChecker.CheckTypeAccess(_typeDest, _binder.Context.ContextForMemberLookup))
                {
                    if (_needsExprDest)
                    {
                        _binder.bindSimpleCast(_exprSrc, _typeDest, 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);
            }
Exemple #26
0
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // RUNTIME BINDER ONLY CHANGE
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        internal CType GetBestAccessibleType(CSemanticChecker semanticChecker, AggregateDeclaration context, CType typeSrc)
        {
            // This method implements the "best accessible type" algorithm for determining the type
            // of untyped arguments in the runtime binder. It is also used in method type inference
            // to fix type arguments to types that are accessible.

            // The new type is returned in an out parameter. The result will be true (and the out param
            // non-null) only when the algorithm could find a suitable accessible type.

            Debug.Assert(semanticChecker != null);
            Debug.Assert(typeSrc != null);
            Debug.Assert(!(typeSrc is ParameterModifierType));
            Debug.Assert(!(typeSrc is PointerType));

            if (semanticChecker.CheckTypeAccess(typeSrc, context))
            {
                // If we already have an accessible type, then use it.
                return(typeSrc);
            }

            // These guys have no accessibility concerns.
            Debug.Assert(!(typeSrc is VoidType) && !(typeSrc is TypeParameterType));

            if (typeSrc is AggregateType aggSrc)
            {
                for (;;)
                {
                    if ((aggSrc.IsInterfaceType || aggSrc.IsDelegateType) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, context, aggSrc, out CType typeDst))
                    {
                        // If we have an interface or delegate type, then it can potentially be varied by its type arguments
                        // to produce an accessible type, and if that's the case, then return that.
                        // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
                        Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, context));
                        return(typeDst);
                    }

                    // We have an AggregateType, so recurse on its base class.
                    AggregateType baseType = aggSrc.BaseClass;
                    if (baseType == null)
                    {
                        // This happens with interfaces, for instance. But in that case, the
                        // conversion to object does exist, is an implicit reference conversion,
                        // and is guaranteed to be accessible, so we will use it.
                        return(GetPredefAgg(PredefinedType.PT_OBJECT).getThisType());
                    }

                    if (semanticChecker.CheckTypeAccess(baseType, context))
                    {
                        return(baseType);
                    }

                    // baseType is always an AggregateType, so no need for logic of other types.
                    aggSrc = baseType;
                }
            }

            if (typeSrc is ArrayType arrSrc)
            {
                if (TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, context, arrSrc, out CType typeDst))
                {
                    // Similarly to the interface and delegate case, arrays are covariant in their element type and
                    // so we can potentially produce an array type that is accessible.
                    // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
                    Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, context));
                    return(typeDst);
                }

                // We have an inaccessible array type for which we could not earlier find a better array type
                // with a covariant conversion, so the best we can do is System.Array.
                return(GetPredefAgg(PredefinedType.PT_ARRAY).getThisType());
            }

            Debug.Assert(typeSrc is NullableType);

            // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
            return(GetPredefAgg(PredefinedType.PT_VALUE).getThisType());
        }
Exemple #27
0
        /***************************************************************************************************
        *   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());
        }
Exemple #28
0
        ////////////////////////////////////////////////////////////////////////////////
        // Check whether typeArgs satisfies the constraints of typeVars. The 
        // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The
        // tree and symErr are used for error reporting.

        private static bool CheckConstraintsCore(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            Debug.Assert(typeVars.size == typeArgs.size);
            Debug.Assert(typeVars.size > 0);
            Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors);

            bool fError = false;

            for (int i = 0; i < typeVars.size; i++)
            {
                // Empty bounds should be set to object.
                TypeParameterType var = typeVars.ItemAsTypeParameterType(i);
                CType arg = typeArgs.Item(i);

                bool fOK = CheckSingleConstraint(checker, errHandling, symErr, var, arg, typeArgsCls, typeArgsMeth, flags);
                fError |= !fOK;
            }

            return !fError;
        }
Exemple #29
0
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // RUNTIME BINDER ONLY CHANGE
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)
        {
            // This method implements the "best accessible type" algorithm for determining the type
            // of untyped arguments in the runtime binder. It is also used in method type inference
            // to fix type arguments to types that are accessible.

            // The new type is returned in an out parameter. The result will be true (and the out param
            // non-null) only when the algorithm could find a suitable accessible type.

            Debug.Assert(semanticChecker != null);
            Debug.Assert(bindingContext != null);
            Debug.Assert(typeSrc != null);

            typeDst = null;

            if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup))
            {
                // If we already have an accessible type, then use it. This is the terminal point of the recursion.
                typeDst = typeSrc;
                return(true);
            }

            // These guys have no accessibility concerns.
            Debug.Assert(!(typeSrc is VoidType) && !(typeSrc is ErrorType) && !(typeSrc is TypeParameterType));

            if (typeSrc is ParameterModifierType || typeSrc is PointerType)
            {
                // We cannot vary these.
                return(false);
            }

            CType intermediateType;

            if (typeSrc is AggregateType aggSrc && (aggSrc.isInterfaceType() || aggSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, aggSrc, out intermediateType))
            {
                // If we have an interface or delegate type, then it can potentially be varied by its type arguments
                // to produce an accessible type, and if that's the case, then return that.
                // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
                return(true);
            }

            if (typeSrc is ArrayType arrSrc && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, arrSrc, out intermediateType))
            {
                // Similarly to the interface and delegate case, arrays are covariant in their element type and
                // so we can potentially produce an array type that is accessible.
                // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
                return(true);
            }

            if (typeSrc is NullableType)
            {
                // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
                typeDst = GetPredefAgg(PredefinedType.PT_VALUE).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
                return(true);
            }

            if (typeSrc is ArrayType)
            {
                // We have an inaccessible array type for which we could not earlier find a better array type
                // with a covariant conversion, so the best we can do is System.Array.
                typeDst = GetPredefAgg(PredefinedType.PT_ARRAY).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
                return(true);
            }

            Debug.Assert(typeSrc is AggregateType);

            if (typeSrc is AggregateType aggType)
            {
                // We have an AggregateType, so recurse on its base class.
                AggregateType baseType = aggType.GetBaseClass();

                if (baseType == null)
                {
                    // This happens with interfaces, for instance. But in that case, the
                    // conversion to object does exist, is an implicit reference conversion,
                    // and so we will use it.
                    baseType = GetPredefAgg(PredefinedType.PT_OBJECT).getThisType();
                }

                return(GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst));
            }

            return(false);
        }
Exemple #30
0
        // 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 is NullableType nub)
            {
                CType typeT = nub.GetAts(checker.GetErrorContext());
                if (typeT != null)
                {
                    type = typeT;
                }
                else
                {
                    type = type.GetNakedType(true);
                }
            }

            if (!(type is AggregateType ats))
            {
                return(true);
            }

            if (ats.GetTypeArgsAll().Count == 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.Count == typeArgsThis.Count);

            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.Count > 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.Count; i++)
            {
                CType arg = typeArgsThis[i].GetNakedType(true);
                if (arg is AggregateType atArg && !atArg.fConstraintsChecked)
                {
                    CheckConstraints(checker, errHandling, atArg, flags | CheckConstraintsFlags.Outer);
                    if (atArg.fConstraintError)
                    {
                        ats.fConstraintError = true;
                    }
                }
            }
            return(!ats.fConstraintError);
        }
Exemple #31
0
        private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType());

            typeDst = null;

            AggregateSymbol aggSym      = typeSrc.GetOwningAggregate();
            AggregateType   aggOpenType = aggSym.getThisType();

            if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup))
            {
                // if the aggregate symbol itself is not accessible, then forget it, there is no
                // variance that will help us arrive at an accessible type.
                return(false);
            }

            TypeArray typeArgs   = typeSrc.GetTypeArgsThis();
            TypeArray typeParams = aggOpenType.GetTypeArgsThis();

            CType[] newTypeArgsTemp = new CType[typeArgs.Count];

            for (int i = 0; i < typeArgs.Count; i++)
            {
                if (semanticChecker.CheckTypeAccess(typeArgs[i], bindingContext.ContextForMemberLookup))
                {
                    // we have an accessible argument, this position is not a problem.
                    newTypeArgsTemp[i] = typeArgs[i];
                    continue;
                }

                if (!typeArgs[i].IsRefType() || !((TypeParameterType)typeParams[i]).Covariant)
                {
                    // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail.
                    return(false);
                }

                CType intermediateTypeArg;
                if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs[i], out intermediateTypeArg))
                {
                    // now we either have a value type (which must be accessible due to the above
                    // check, OR we have an inaccessible type (which must be a ref type). In either
                    // case, the recursion worked out and we are OK to vary this argument.
                    newTypeArgsTemp[i] = intermediateTypeArg;
                    continue;
                }
                else
                {
                    Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter");
                    return(false);
                }
            }

            TypeArray newTypeArgs      = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp);
            CType     intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs);

            // All type arguments were varied successfully, which means now we must be accessible. But we could
            // have violated constraints. Let's check that out.

            if (!TypeBind.CheckConstraints(semanticChecker, null /*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors))
            {
                return(false);
            }

            typeDst = intermediateType;
            Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
            return(true);
        }
Exemple #32
0
        private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);

            if (arg is OpenTypePlaceholderType)
            {
                return(true);
            }

            if (arg is ErrorType)
            {
                // Error should have been reported previously.
                return(false);
            }

            if (checker.CheckBogus(arg))
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg);
                }

                return(false);
            }

            if (arg is PointerType)
            {
                if (fReportErrors)
                {
                    errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg);
                }

                return(false);
            }

            if (arg.isStaticClass())
            {
                if (fReportErrors)
                {
                    checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass);
                }

                return(false);
            }

            bool fError = false;

            if (var.HasRefConstraint() && !arg.IsRefType())
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                }

                fError = true;
            }

            TypeArray bnds     = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth);
            int       itypeMin = 0;

            if (var.HasValConstraint())
            {
                // If we have a type variable that is constrained to a value type, then we
                // want to check if its a nullable type, so that we can report the
                // constraint error below. In order to do this however, we need to check
                // that either the type arg is not a value type, or it is a nullable type.
                //
                // To check whether or not its a nullable type, we need to get the resolved
                // bound from the type argument and check against that.

                bool bIsValueType = arg.IsValType();
                bool bIsNullable  = arg is NullableType;
                if (bIsValueType && arg is TypeParameterType typeArg)
                {
                    TypeArray pArgBnds = typeArg.GetBounds();
                    if (pArgBnds.Count > 0)
                    {
                        bIsNullable = pArgBnds[0] is NullableType;
                    }
                }

                if (!bIsValueType || bIsNullable)
                {
                    if (fReportErrors)
                    {
                        errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                    }

                    fError = true;
                }

                // Since FValCon() is set it is redundant to check System.ValueType as well.
                if (bnds.Count != 0 && bnds[0].isPredefType(PredefinedType.PT_VALUE))
                {
                    itypeMin = 1;
                }
            }

            for (int j = itypeMin; j < bnds.Count; j++)
            {
                CType typeBnd = bnds[j];
                if (!SatisfiesBound(checker, arg, typeBnd))
                {
                    if (fReportErrors)
                    {
                        // The bound isn't satisfied because of a constraint type. Explain to the user why not.
                        // There are 4 main cases, based on the type of the supplied type argument:
                        //  - reference type, or type parameter known to be a reference type
                        //  - nullable type, from which there is a boxing conversion to the constraint type(see below for details)
                        //  - type variable
                        //  - value type
                        // These cases are broken out because: a) The sets of conversions which can be used
                        // for constraint satisfaction is different based on the type argument supplied,
                        // and b) Nullable is one funky type, and user's can use all the help they can get
                        // when using it.
                        ErrorCode error;
                        if (arg.IsRefType())
                        {
                            // A reference type can only satisfy bounds to types
                            // to which they have an implicit reference conversion
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
                        }
                        else if (arg is NullableType nubArg && checker.GetSymbolLoader().HasBaseConversion(nubArg.GetUnderlyingType(), typeBnd))    // This is inlining FBoxingConv
                        {
                            // nullable types do not satisfy bounds to every type that they are boxable to
                            // They only satisfy bounds of object and ValueType
                            if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || nubArg.GetUnderlyingType() == typeBnd)
                            {
                                // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
                                // even though the conversion from Nullable to these types is a boxing conversion
                                // This is a rare case, because these bounds can never be directly stated ...
                                // These bounds can only occur when one type paramter is constrained to a second type parameter
                                // and the second type parameter is instantiated with Enum or the underlying type of the first type
                                // parameter
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
                            }
                            else
                            {
                                // Nullable types don't satisfy the bounds of any interface type
                                // even when there is a boxing conversion from the Nullable type to
                                // the interface type. This will be a relatively common scenario
                                // so we cal it out separately from the previous case.
                                Debug.Assert(typeBnd.isInterfaceType());
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
                            }
                        }
                        else if (arg is TypeParameterType)
                        {
                            // Type variables can satisfy bounds through boxing and type variable conversions
                            Debug.Assert(!arg.IsRefType());
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar;
                        }
                        else
                        {
                            // Value types can only satisfy bounds through boxing conversions.
                            // Note that the exceptional case of Nullable types and boxing is handled above.
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
                        }
                        errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique));
                    }
                    fError = true;
                }
            }
Exemple #33
0
        private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType());

            typeDst = null;

            AggregateSymbol aggSym = typeSrc.GetOwningAggregate();
            AggregateType aggOpenType = aggSym.getThisType();

            if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup()))
            {
                // if the aggregate symbol itself is not accessible, then forget it, there is no
                // variance that will help us arrive at an accessible type.
                return false;
            }

            TypeArray typeArgs = typeSrc.GetTypeArgsThis();
            TypeArray typeParams = aggOpenType.GetTypeArgsThis();
            CType[] newTypeArgsTemp = new CType[typeArgs.size];

            for (int i = 0; i < typeArgs.size; i++)
            {
                if (semanticChecker.CheckTypeAccess(typeArgs.Item(i), bindingContext.ContextForMemberLookup()))
                {
                    // we have an accessible argument, this position is not a problem.
                    newTypeArgsTemp[i] = typeArgs.Item(i);
                    continue;
                }

                if (!typeArgs.Item(i).IsRefType() || !typeParams.Item(i).AsTypeParameterType().Covariant)
                {
                    // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail.
                    return false;
                }

                CType intermediateTypeArg;
                if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs.Item(i), out intermediateTypeArg))
                {
                    // now we either have a value type (which must be accessible due to the above
                    // check, OR we have an inaccessible type (which must be a ref type). In either
                    // case, the recursion worked out and we are OK to vary this argument.
                    newTypeArgsTemp[i] = intermediateTypeArg;
                    continue;
                }
                else
                {
                    Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter");
                    return false;
                }
            }

            TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.size, newTypeArgsTemp);
            CType intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs);

            // All type arguments were varied successfully, which means now we must be accessible. But we could
            // have violated constraints. Let's check that out.

            if (!TypeBind.CheckConstraints(semanticChecker, null/*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors))
            {
                return false;
            }

            typeDst = intermediateType;
            Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
            return true;
        }
Exemple #34
0
        private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, ArrayType typeSrc, out CType typeDst)
        {
            Debug.Assert(typeSrc != null);

            typeDst = null;

            // We are here because we have an array type with an inaccessible element type. If possible,
            // we should create a new array type that has an accessible element type for which a
            // conversion exists.

            CType elementType = typeSrc.GetElementType();
            if (!elementType.IsRefType())
            {
                // Covariant array conversions exist for reference types only.
                return false;
            }

            CType intermediateType;
            if (GetBestAccessibleType(semanticChecker, bindingContext, elementType, out intermediateType))
            {
                typeDst = this.GetArray(intermediateType, typeSrc.rank);

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            return false;
        }
Exemple #35
0
        public Exception ReportErrors()
        {
            Debug.Assert(FError());

            // Report error.
            // NOTE: If the definition of FError changes, this code will need to change.
            Debug.Assert(!_swtFirst || _swtAmbig);

            if (_swtFirst)
            {
                // Ambiguous lookup.
                return(ErrorHandling.Error(ErrorCode.ERR_AmbigMember, _swtFirst, _swtAmbig));
            }

            if (_swtInaccess)
            {
                return(!_swtInaccess.Sym.isUserCallable() && ((_flags & MemLookFlags.UserCallable) != 0)
                    ? ErrorHandling.Error(ErrorCode.ERR_CantCallSpecialMethod, _swtInaccess)
                    : CSemanticChecker.ReportAccessError(_swtInaccess, _symWhere, _typeQual));
            }

            if ((_flags & MemLookFlags.Ctor) != 0)
            {
                Debug.Assert(_typeSrc is AggregateType);
                return(_arity > 0
                    ? ErrorHandling.Error(ErrorCode.ERR_BadCtorArgCount, ((AggregateType)_typeSrc).OwningAggregate, _arity)
                    : ErrorHandling.Error(ErrorCode.ERR_NoConstructors, ((AggregateType)_typeSrc).OwningAggregate));
            }

            if ((_flags & MemLookFlags.Operator) != 0)
            {
                return(ErrorHandling.Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name));
            }

            if ((_flags & MemLookFlags.Indexer) != 0)
            {
                return(ErrorHandling.Error(ErrorCode.ERR_BadIndexLHS, _typeSrc));
            }

            if (_swtBad)
            {
                return(ErrorHandling.Error((_flags & MemLookFlags.MustBeInvocable) != 0 ? ErrorCode.ERR_NonInvocableMemberCalled : ErrorCode.ERR_CantCallSpecialMethod, _swtBad));
            }

            if (_swtBogus)
            {
                return(ReportBogus(_swtBogus));
            }

            if (_swtBadArity)
            {
                Debug.Assert(_arity != 0);
                Debug.Assert(!(_swtBadArity.Sym is AggregateSymbol));
                if (_swtBadArity.Sym is MethodSymbol badMeth)
                {
                    int cvar = badMeth.typeVars.Count;
                    return(ErrorHandling.Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar));
                }

                return(ErrorHandling.Error(ErrorCode.ERR_TypeArgsNotAllowed, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym)));
            }

            return(ErrorHandling.Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name));
        }
Exemple #36
0
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // RUNTIME BINDER ONLY CHANGE
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)
        {
            // This method implements the "best accessible type" algorithm for determining the type
            // of untyped arguments in the runtime binder. It is also used in method type inference
            // to fix type arguments to types that are accessible.

            // The new type is returned in an out parameter. The result will be true (and the out param
            // non-null) only when the algorithm could find a suitable accessible type.

            Debug.Assert(semanticChecker != null);
            Debug.Assert(bindingContext != null);
            Debug.Assert(typeSrc != null);

            typeDst = null;

            if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup()))
            {
                // If we already have an accessible type, then use it. This is the terminal point of the recursion.
                typeDst = typeSrc;
                return true;
            }

            // These guys have no accessibility concerns.
            Debug.Assert(!typeSrc.IsVoidType() && !typeSrc.IsErrorType() && !typeSrc.IsTypeParameterType());

            if (typeSrc.IsParameterModifierType() || typeSrc.IsPointerType())
            {
                // We cannot vary these.
                return false;
            }

            CType intermediateType;
            if ((typeSrc.isInterfaceType() || typeSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsAggregateType(), out intermediateType))
            {
                // If we have an interface or delegate type, then it can potentially be varied by its type arguments
                // to produce an accessible type, and if that's the case, then return that.
                // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsArrayType() && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsArrayType(), out intermediateType))
            {
                // Similarly to the interface and delegate case, arrays are covariant in their element type and
                // so we can potentially produce an array type that is accessible.
                // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsNullableType())
            {
                // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
                typeDst = this.GetOptPredefAgg(PredefinedType.PT_VALUE).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsArrayType())
            {
                // We have an inaccessible array type for which we could not earlier find a better array type
                // with a covariant conversion, so the best we can do is System.Array.
                typeDst = this.GetReqPredefAgg(PredefinedType.PT_ARRAY).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            Debug.Assert(typeSrc.IsAggregateType());

            if (typeSrc.IsAggregateType())
            {
                // We have an AggregateType, so recurse on its base class.
                AggregateType aggType = typeSrc.AsAggregateType();
                AggregateType baseType = aggType.GetBaseClass();

                if (baseType == null)
                {
                    // This happens with interfaces, for instance. But in that case, the
                    // conversion to object does exist, is an implicit reference conversion,
                    // and so we will use it.
                    baseType = this.GetReqPredefAgg(PredefinedType.PT_OBJECT).getThisType();
                }

                return GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst);
            }

            return false;
        }
Exemple #37
0
        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 = !CSemanticChecker.CheckTypeAccess(typeCur, _symWhere);

            if (fInaccess && (_csym != 0 || _swtInaccess != null))
            {
                return(false);
            }

            // Loop through symbols.
            Symbol symCur;

            for (symCur = SymbolLoader.LookupAggMember(_name, typeCur.OwningAggregate, symbmask_t.MASK_Member);
                 symCur != null;
                 symCur = symCur.LookupNext(symbmask_t.MASK_Member))
            {
                Debug.Assert(!(symCur is AggregateSymbol));
                // Check for arity.
                // 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.
                // All others are only considered when arity is zero.
                if (_arity > 0 && (!(symCur is MethodSymbol curMeth) || curMeth.typeVars.Count != _arity))
                {
                    if (!_swtBadArity)
                    {
                        _swtBadArity.Set(symCur, typeCur);
                    }

                    continue;
                }

                // Check for user callability.
                if (symCur.IsOverride() && !symCur.IsHideByName())
                {
                    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.
                    // This is too liberal, but maintained for compatibility.
                    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 || !CSemanticChecker.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;
                        }
                        // 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.DiffHidden)
                        {
                            // Give method groups priority.
                            if (!(_swtFirst.Sym is MethodSymbol))
                            {
                                goto LAmbig;
                            }
                        }
                        // 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);
        }
Exemple #38
0
            public bool CanUseCurrentSymbol()
            {
                _bCurrentSymIsInaccessible = false;
                _bCurrentSymIsBogus        = false;

                // Make sure that whether we're seeing a ctor is consistent with the flag.
                // The only properties we handle are indexers.
                if (_mask == symbmask_t.MASK_MethodSymbol && (
                        0 == (_flags & EXPRFLAG.EXF_CTOR) != !((MethodSymbol)_pCurrentSym).IsConstructor() ||
                        0 == (_flags & EXPRFLAG.EXF_OPERATOR) != !((MethodSymbol)_pCurrentSym).isOperator) ||
                    _mask == symbmask_t.MASK_PropertySymbol && !(_pCurrentSym is IndexerSymbol))
                {
                    // Get the next symbol.
                    return(false);
                }

                // If our arity is non-0, we must match arity with this symbol.
                if (_nArity > 0)
                {
                    if (_mask == symbmask_t.MASK_MethodSymbol && ((MethodSymbol)_pCurrentSym).typeVars.Count != _nArity)
                    {
                        return(false);
                    }
                }

                // If this guy's not callable, no good.
                if (!ExpressionBinder.IsMethPropCallable(_pCurrentSym, (_flags & EXPRFLAG.EXF_USERCALLABLE) != 0))
                {
                    return(false);
                }

                // Check access.
                if (!GetSemanticChecker().CheckAccess(_pCurrentSym, _pCurrentType, _pContext, _pQualifyingType))
                {
                    // Sym is not accessible. However, if we're allowing inaccessible, then let it through and mark it.
                    if (_bAllowBogusAndInaccessible)
                    {
                        _bCurrentSymIsInaccessible = true;
                    }
                    else
                    {
                        return(false);
                    }
                }

                // Check bogus.
                if (CSemanticChecker.CheckBogus(_pCurrentSym))
                {
                    // Sym is bogus, but if we're allow it, then let it through and mark it.
                    if (_bAllowBogusAndInaccessible)
                    {
                        _bCurrentSymIsBogus = true;
                    }
                    else
                    {
                        return(false);
                    }
                }

                // if we are done checking all the instance types ensure that currentsym is an
                // extension method and not a simple static method
                if (!_bIsCheckingInstanceMethods && !((MethodSymbol)_pCurrentSym).IsExtension())
                {
                    return(false);
                }

                return(true);
            }
Exemple #39
0
        /***************************************************************************************************
            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();
        }
Exemple #40
0
        ////////////////////////////////////////////////////////////////////////////////
        // Determine whether the arg type satisfies the typeBnd constraint. Note that 
        // typeBnd could be just about any type (since we added naked type parameter
        // constraints).

        private static bool SatisfiesBound(CSemanticChecker checker, CType arg, CType typeBnd)
        {
            if (typeBnd == arg)
                return true;

            switch (typeBnd.GetTypeKind())
            {
                default:
                    Debug.Assert(false, "Unexpected type.");
                    return false;

                case TypeKind.TK_VoidType:
                case TypeKind.TK_PointerType:
                case TypeKind.TK_ErrorType:
                    return false;

                case TypeKind.TK_ArrayType:
                case TypeKind.TK_TypeParameterType:
                    break;

                case TypeKind.TK_NullableType:
                    typeBnd = typeBnd.AsNullableType().GetAts(checker.GetErrorContext());
                    if (null == typeBnd)
                        return true;
                    break;

                case TypeKind.TK_AggregateType:
                    break;
            }

            Debug.Assert(typeBnd.IsAggregateType() || typeBnd.IsTypeParameterType() || typeBnd.IsArrayType());

            switch (arg.GetTypeKind())
            {
                default:
                    return false;
                case TypeKind.TK_ErrorType:
                case TypeKind.TK_PointerType:
                    return false;
                case TypeKind.TK_NullableType:
                    arg = arg.AsNullableType().GetAts(checker.GetErrorContext());
                    if (null == arg)
                        return true;
                    // Fall through.
                    goto case TypeKind.TK_TypeParameterType;
                case TypeKind.TK_TypeParameterType:
                case TypeKind.TK_ArrayType:
                case TypeKind.TK_AggregateType:
                    return checker.GetSymbolLoader().HasBaseConversion(arg, typeBnd);
            }
        }
Exemple #41
0
        ////////////////////////////////////////////////////////////////////////////////
        // Check the constraints on the method instantiation.
        public static void CheckMethConstraints(CSemanticChecker checker, ErrorHandling errCtx, MethWithInst mwi)
        {
            Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null);
            Debug.Assert(mwi.Meth().typeVars.size == mwi.TypeArgs.size);
            Debug.Assert(mwi.GetType().getAggregate() == mwi.Meth().getClass());

            if (mwi.TypeArgs.size > 0)
            {
                CheckConstraintsCore(checker, errCtx, mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().GetTypeArgsAll(), mwi.TypeArgs, CheckConstraintsFlags.None);
            }
        }
        // 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 is AggregateType ats))
            {
                if (type is NullableType nub)
                {
                    ats = nub.GetAts();
                }
                else
                {
                    return(true);
                }
            }

            if (ats.TypeArgsAll.Count == 0)
            {
                // Common case: there are no type vars, so there are no constraints.
                ats.ConstraintError = false;
                return(true);
            }

            // Already checked.
            if (ats.ConstraintError.HasValue)
            {
                // No errors
                if (!ats.ConstraintError.GetValueOrDefault())
                {
                    return(true);
                }

                // We want the result, not an exception.
                if ((flags & CheckConstraintsFlags.NoErrors) != 0)
                {
                    return(false);
                }
            }

            TypeArray typeVars     = ats.OwningAggregate.GetTypeVars();
            TypeArray typeArgsThis = ats.TypeArgsThis;
            TypeArray typeArgsAll  = ats.TypeArgsAll;

            Debug.Assert(typeVars.Count == typeArgsThis.Count);

            // 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.ConstraintError.HasValue))
            {
                if (!CheckConstraints(checker, errHandling, ats.OuterType, flags))
                {
                    ats.ConstraintError = true;
                    return(false);
                }
            }

            if (typeVars.Count > 0)
            {
                if (!CheckConstraintsCore(checker, errHandling, ats.OwningAggregate, typeVars, typeArgsThis, typeArgsAll, null, flags & CheckConstraintsFlags.NoErrors))
                {
                    ats.ConstraintError = true;
                    return(false);
                }
            }

            // Now check type args themselves.
            for (int i = 0; i < typeArgsThis.Count; i++)
            {
                CType arg = typeArgsThis[i].GetNakedType(true);
                if (arg is AggregateType atArg && !atArg.ConstraintError.HasValue)
                {
                    CheckConstraints(checker, errHandling, atArg, flags | CheckConstraintsFlags.Outer);
                    if (atArg.ConstraintError.GetValueOrDefault())
                    {
                        ats.ConstraintError = true;
                        return(false);
                    }
                }
            }

            ats.ConstraintError = false;
            return(true);
        }