// Generate an error if CType is static. public bool CheckForStaticClass(Symbol symCtx, CType CType, ErrorCode err) { if (!CType.isStaticClass()) return false; ReportStaticClassError(symCtx, CType, err); return true; }
public virtual ACCESSERROR CheckAccess2(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { Debug.Assert(symCheck != null); Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate()); Debug.Assert(typeThru == null || typeThru.IsAggregateType() || typeThru.IsTypeParameterType() || typeThru.IsArrayType() || typeThru.IsNullableType() || typeThru.IsErrorType()); #if DEBUG switch (symCheck.getKind()) { default: break; case SYMKIND.SK_MethodSymbol: case SYMKIND.SK_PropertySymbol: case SYMKIND.SK_FieldSymbol: case SYMKIND.SK_EventSymbol: Debug.Assert(atsCheck != null); break; } #endif // DEBUG ACCESSERROR error = CheckAccessCore(symCheck, atsCheck, symWhere, typeThru); if (ACCESSERROR.ACCESSERROR_NOERROR != error) { return error; } // Check the accessibility of the return CType. CType CType = symCheck.getType(); if (CType == null) { return ACCESSERROR.ACCESSERROR_NOERROR; } // For members of AGGSYMs, atsCheck should always be specified! Debug.Assert(atsCheck != null); if (atsCheck.getAggregate().IsSource()) { // We already check the "at least as accessible as" rules. // Does this always work for generics? // Could we get a bad CType argument in typeThru? // Maybe call CheckTypeAccess on typeThru? return ACCESSERROR.ACCESSERROR_NOERROR; } // Substitute on the CType. if (atsCheck.GetTypeArgsAll().size > 0) { CType = SymbolLoader.GetTypeManager().SubstType(CType, atsCheck); } return CheckTypeAccess(CType, symWhere) ? ACCESSERROR.ACCESSERROR_NOERROR : ACCESSERROR.ACCESSERROR_NOACCESS; }
// This adds the sym to the child list but doesn't associate it // in the symbol table. public void AddToChildList(Symbol sym) { Debug.Assert(sym != null /*&& this != null */); // If parent is set it should be set to us! Debug.Assert(sym.parent == null || sym.parent == this); // There shouldn't be a nextChild. Debug.Assert(sym.nextChild == null); if (_lastChild == null) { Debug.Assert(firstChild == null); firstChild = _lastChild = sym; } else { _lastChild.nextChild = sym; _lastChild = sym; sym.nextChild = null; #if DEBUG // Validate our chain. Symbol psym; int count = 400; // Limited the length of chain that we'll run - so debug perf isn't too bad. for (psym = this.firstChild; psym != null && psym.nextChild != null && --count > 0;) psym = psym.nextChild; Debug.Assert(_lastChild == psym || count == 0); #endif } sym.parent = this; }
public void InsertChild(ParentSymbol parent, Symbol child) { Debug.Assert(child.nextSameName == null); Debug.Assert(child.parent == null || child.parent == parent); child.parent = parent; // Place the child into the hash table. InsertChildNoGrow(child); }
private static Symbol FindCorrectKind(Symbol sym, symbmask_t kindmask) { do { if ((kindmask & sym.mask()) != 0) { return sym; } sym = sym.nextSameName; } while (sym != null); return null; }
private void InsertChildNoGrow(Symbol child) { Key k = new Key(child.name, child.parent); Symbol sym; if (_dictionary.TryGetValue(k, out sym)) { // Link onto the end of the symbol chain here. while (sym != null && sym.nextSameName != null) { sym = sym.nextSameName; } Debug.Assert(sym != null && sym.nextSameName == null); sym.nextSameName = child; return; } else { _dictionary.Add(k, child); } }
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; }
//////////////////////////////////////////////////////////////////////////////// // 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; }
protected void ErrAppendParentCore(Symbol parent, SubstContext pctx) { if (null == parent) return; if (parent == getBSymmgr().GetRootNS()) return; if (pctx != null && !pctx.FNop() && parent.IsAggregateSymbol() && 0 != parent.AsAggregateSymbol().GetTypeVarsAll().size) { CType pType = GetTypeManager().SubstType(parent.AsAggregateSymbol().getThisType(), pctx); ErrAppendType(pType, null); } else { ErrAppendSym(parent, null); } ErrAppendChar('.'); }
public SymWithType(Symbol sym, AggregateType ats) { Set(sym, ats); }
public virtual bool CheckTypeAccess(CType type, Symbol symWhere) { Debug.Assert(type != null); // Array, Ptr, Nub, etc don't matter. type = type.GetNakedType(true); if (!type.IsAggregateType()) { Debug.Assert(type.IsVoidType() || type.IsErrorType() || type.IsTypeParameterType()); return true; } for (AggregateType ats = type.AsAggregateType(); ats != null; ats = ats.outerType) { if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.GetOwningAggregate(), ats.outerType, symWhere, null)) { return false; } } TypeArray typeArgs = type.AsAggregateType().GetTypeArgsAll(); for (int i = 0; i < typeArgs.size; i++) { if (!CheckTypeAccess(typeArgs.Item(i), symWhere)) return false; } return true; }
public void ErrAppendSym(Symbol sym, SubstContext pctx, bool fArgs) { switch (sym.getKind()) { case SYMKIND.SK_NamespaceDeclaration: // for namespace declarations just convert the namespace ErrAppendSym(sym.AsNamespaceDeclaration().NameSpace(), null); break; case SYMKIND.SK_GlobalAttributeDeclaration: ErrAppendName(sym.name); break; case SYMKIND.SK_AggregateDeclaration: ErrAppendSym(sym.AsAggregateDeclaration().Agg(), pctx); break; case SYMKIND.SK_AggregateSymbol: { // Check for a predefined class with a special "nice" name for // error reported. string text = PredefinedTypes.GetNiceName(sym.AsAggregateSymbol()); if (text != null) { // Found a nice name. ErrAppendString(text); } else if (sym.AsAggregateSymbol().IsAnonymousType()) { ErrAppendId(MessageID.AnonymousType); break; } else { ErrAppendParentSym(sym, pctx); ErrAppendName(sym.name); ErrAppendTypeParameters(sym.AsAggregateSymbol().GetTypeVars(), pctx, true); } break; } case SYMKIND.SK_MethodSymbol: ErrAppendMethod(sym.AsMethodSymbol(), pctx, fArgs); break; case SYMKIND.SK_PropertySymbol: ErrAppendProperty(sym.AsPropertySymbol(), pctx); break; case SYMKIND.SK_EventSymbol: ErrAppendEvent(sym.AsEventSymbol(), pctx); break; case SYMKIND.SK_AssemblyQualifiedNamespaceSymbol: case SYMKIND.SK_NamespaceSymbol: if (sym == getBSymmgr().GetRootNS()) { ErrAppendId(MessageID.GlobalNamespace); } else { ErrAppendParentSym(sym, null); ErrAppendName(sym.name); } break; case SYMKIND.SK_FieldSymbol: ErrAppendParentSym(sym, pctx); ErrAppendName(sym.name); break; case SYMKIND.SK_TypeParameterSymbol: if (null == sym.name) { // It's a standard type variable. if (sym.AsTypeParameterSymbol().IsMethodTypeParameter()) ErrAppendChar('!'); ErrAppendChar('!'); ErrAppendPrintf("{0}", sym.AsTypeParameterSymbol().GetIndexInTotalParameters()); } else ErrAppendName(sym.name); break; case SYMKIND.SK_LocalVariableSymbol: case SYMKIND.SK_LabelSymbol: case SYMKIND.SK_TransparentIdentifierMemberSymbol: // Generate symbol name. ErrAppendName(sym.name); break; case SYMKIND.SK_Scope: case SYMKIND.SK_LambdaScope: default: // Shouldn't happen. Debug.Assert(false, "Bad symbol kind"); break; } }
// // SymbolLoader forwarders (end) ///////////////////////////////////////////////////////////////////////////////// // // Utility methods // protected ACCESSERROR CheckAccessCore(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { Debug.Assert(symCheck != null); Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate()); Debug.Assert(typeThru == null || typeThru.IsAggregateType() || typeThru.IsTypeParameterType() || typeThru.IsArrayType() || typeThru.IsNullableType() || typeThru.IsErrorType()); switch (symCheck.GetAccess()) { default: throw Error.InternalCompilerError(); //return ACCESSERROR.ACCESSERROR_NOACCESS; case ACCESS.ACC_UNKNOWN: return ACCESSERROR.ACCESSERROR_NOACCESS; case ACCESS.ACC_PUBLIC: return ACCESSERROR.ACCESSERROR_NOERROR; case ACCESS.ACC_PRIVATE: case ACCESS.ACC_PROTECTED: if (symWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } break; case ACCESS.ACC_INTERNAL: case ACCESS.ACC_INTERNALPROTECTED: // Check internal, then protected. if (symWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } if (symWhere.SameAssemOrFriend(symCheck)) { return ACCESSERROR.ACCESSERROR_NOERROR; } if (symCheck.GetAccess() == ACCESS.ACC_INTERNAL) { return ACCESSERROR.ACCESSERROR_NOACCESS; } break; } // Should always have atsCheck for private and protected access check. // We currently don't need it since access doesn't respect instantiation. // We just use symWhere.parent.AsAggregateSymbol() instead. AggregateSymbol aggCheck = symCheck.parent.AsAggregateSymbol(); // Find the inner-most enclosing AggregateSymbol. AggregateSymbol aggWhere = null; for (Symbol symT = symWhere; symT != null; symT = symT.parent) { if (symT.IsAggregateSymbol()) { aggWhere = symT.AsAggregateSymbol(); break; } if (symT.IsAggregateDeclaration()) { aggWhere = symT.AsAggregateDeclaration().Agg(); break; } } if (aggWhere == null) { return ACCESSERROR.ACCESSERROR_NOACCESS; } // First check for private access. for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { if (agg == aggCheck) { return ACCESSERROR.ACCESSERROR_NOERROR; } } if (symCheck.GetAccess() == ACCESS.ACC_PRIVATE) { return ACCESSERROR.ACCESSERROR_NOACCESS; } // Handle the protected case - which is the only real complicated one. Debug.Assert(symCheck.GetAccess() == ACCESS.ACC_PROTECTED || symCheck.GetAccess() == ACCESS.ACC_INTERNALPROTECTED); // Check if symCheck is in aggWhere or a base of aggWhere, // or in an outer agg of aggWhere or a base of an outer agg of aggWhere. AggregateType atsThru = null; if (typeThru != null && !symCheck.isStatic) { atsThru = SymbolLoader.GetAggTypeSym(typeThru); } // Look for aggCheck among the base classes of aggWhere and outer aggs. bool found = false; for (AggregateSymbol agg = aggWhere; agg != null; agg = agg.GetOuterAgg()) { Debug.Assert(agg != aggCheck); // We checked for this above. // Look for aggCheck among the base classes of agg. if (agg.FindBaseAgg(aggCheck)) { found = true; // aggCheck is a base class of agg. Check atsThru. // For non-static protected access to be legal, atsThru must be an instantiation of // agg or a CType derived from an instantiation of agg. In this case // all that matters is that agg is in the base AggregateSymbol chain of atsThru. The // actual AGGTYPESYMs involved don't matter. if (atsThru == null || atsThru.getAggregate().FindBaseAgg(agg)) { return ACCESSERROR.ACCESSERROR_NOERROR; } } } // the CType in which the method is being called has no relationship with the // CType on which the method is defined surely this is NOACCESS and not NOACCESSTHRU if (found == false) return ACCESSERROR.ACCESSERROR_NOACCESS; return (atsThru == null) ? ACCESSERROR.ACCESSERROR_NOACCESS : ACCESSERROR.ACCESSERROR_NOACCESSTHRU; }
public ErrArg(Symbol pSym, ErrArgFlags eaf) { this.eak = ErrArgKind.Sym; this.eaf = eaf; this.sym = pSym; }
public ErrArg(Symbol pSym) : this(pSym, ErrArgFlags.None) { }
public Symbol LookupNextSym(Symbol sym, ParentSymbol parent, symbmask_t kindmask) { return BSYMMGR.LookupNextSym(sym, parent, kindmask); }
public bool SameAssemOrFriend(Symbol sym) { Assembly assem = GetAssembly(); return assem == sym.GetAssembly() || sym.InternalsVisibleTo(assem); }
public bool CheckBogus(Symbol sym) { if (sym == null) { return false; } if (!sym.hasBogus()) { bool fBogus = sym.computeCurrentBogusState(); if (fBogus) { // Only set this if everything is declared or // at least 1 declared thing is bogus sym.setBogus(fBogus); } } return sym.hasBogus() && sym.checkBogus(); }
// Generates an error for static classes public void ReportStaticClassError(Symbol symCtx, CType CType, ErrorCode err) { if (symCtx != null) ErrorContext.Error(err, CType, new ErrArgRef(symCtx)); else ErrorContext.Error(err, CType); }
public void ReportAccessError(SymWithType swtBad, Symbol symWhere, CType typeQual) { Debug.Assert(!CheckAccess(swtBad.Sym, swtBad.GetType(), symWhere, typeQual) || !CheckTypeAccess(swtBad.GetType(), symWhere)); if (CheckAccess2(swtBad.Sym, swtBad.GetType(), symWhere, typeQual) == ACCESSERROR.ACCESSERROR_NOACCESSTHRU) { ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, swtBad, typeQual, symWhere); } else { ErrorContext.ErrorRef(ErrorCode.ERR_BadAccess, swtBad); } }
public ErrArg(SymWithType swt) { this.eak = ErrArgKind.SymWithType; this.eaf = ErrArgFlags.None; this.swtMemo = new SymWithTypeMemo(); this.swtMemo.sym = swt.Sym; this.swtMemo.ats = swt.Ats; }
/* * Create a fill-in string describing a symbol. */ public void ErrAppendSym(Symbol sym, SubstContext pctx) { ErrAppendSym(sym, pctx, true); }
public ErrArg(MethPropWithInst mpwi) { this.eak = ErrArgKind.MethWithInst; this.eaf = ErrArgFlags.None; this.mpwiMemo = new MethPropWithInstMemo(); this.mpwiMemo.sym = mpwi.Sym; this.mpwiMemo.ats = mpwi.Ats; this.mpwiMemo.typeArgs = mpwi.TypeArgs; }
public ErrArgRef(Symbol sym) : base(sym) { this.eaf = ErrArgFlags.Ref; }
public bool CheckAccess(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) { return CheckAccess2(symCheck, atsCheck, symWhere, typeThru) == ACCESSERROR.ACCESSERROR_NOERROR; }
public ErrArgRefOnly(Symbol sym) : base(sym) { eaf = ErrArgFlags.RefOnly; }
public void Set(Symbol sym, AggregateType ats) { if (sym == null) ats = null; Debug.Assert(ats == null || sym.parent == ats.getAggregate()); _sym = sym; _ats = ats; }
public ErrArgSymKind(Symbol sym) { eak = ErrArgKind.SymKind; eaf = ErrArgFlags.None; sk = sym.getKind(); if (sk == SYMKIND.SK_AssemblyQualifiedNamespaceSymbol) { if (!String.IsNullOrEmpty(sym.AsAssemblyQualifiedNamespaceSymbol().GetNS().name.Text)) { // Non-empty namespace name means it's not the root // so treat it like a namespace instead of an alias sk = SYMKIND.SK_NamespaceSymbol; } else { // An empty namespace name means it's just an alias for the root sk = SYMKIND.SK_ExternalAliasDefinitionSymbol; } } }
public virtual void Clear() { _sym = null; _ats = null; }
protected void ErrAppendParentSym(Symbol sym, SubstContext pctx) { ErrAppendParentCore(sym.parent, pctx); }