1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Linq;
9 using Microsoft.CSharp.RuntimeBinder.Errors;
10 using Microsoft.CSharp.RuntimeBinder.Syntax;
11 
12 namespace Microsoft.CSharp.RuntimeBinder.Semantics
13 {
14     [Flags]
15     internal enum MemLookFlags : uint
16     {
17         None = 0,
18 
19         Ctor = EXPRFLAG.EXF_CTOR,
20         NewObj = EXPRFLAG.EXF_NEWOBJCALL,
21         Operator = EXPRFLAG.EXF_OPERATOR,
22         Indexer = EXPRFLAG.EXF_INDEXER,
23         UserCallable = EXPRFLAG.EXF_USERCALLABLE,
24         BaseCall = EXPRFLAG.EXF_BASECALL,
25 
26         // All EXF flags are < 0x01000000
27         MustBeInvocable = 0x20000000,
28 
29         All = Ctor | NewObj | Operator | Indexer | UserCallable | BaseCall | MustBeInvocable
30     }
31 
32     /////////////////////////////////////////////////////////////////////////////////
33     // MemberLookup class handles looking for a member within a type and its
34     // base types. This only handles AGGTYPESYMs and TYVARSYMs.
35     //
36     // Lookup must be called before any other methods.
37 
38     internal sealed class MemberLookup
39     {
40         // The inputs to Lookup.
41         private CSemanticChecker _pSemanticChecker;
42         private SymbolLoader _pSymbolLoader;
43         private CType _typeSrc;
44         private Expr _obj;
45         private CType _typeQual;
46         private ParentSymbol _symWhere;
47         private Name _name;
48         private int _arity;
49         private MemLookFlags _flags;
50 
51         // For maintaining the type array. We throw the first 8 or so here.
52         private readonly List<AggregateType> _rgtypeStart;
53 
54         // Results of the lookup.
55         private List<AggregateType> _prgtype;
56         private int _csym;                 // Number of syms found.
57         private readonly SymWithType _swtFirst;     // The first symbol found.
58         private readonly List<MethPropWithType> _methPropWithTypeList; // When we look up methods, we want to keep the list of all candidate methods given a particular name.
59 
60         // These are for error reporting.
61         private readonly SymWithType _swtAmbig;     // An ambiguous symbol.
62         private readonly SymWithType _swtInaccess;  // An inaccessible symbol.
63         private readonly SymWithType _swtBad;       // If we're looking for a constructor or indexer, this matched on name, but isn't the right thing.
64         private readonly SymWithType _swtBogus;     // A bogus member - such as an indexed property.
65         private readonly SymWithType _swtBadArity;  // An symbol with the wrong arity.
66         private bool _fMulti;              // Whether symFirst is of a kind for which we collect multiples (methods and indexers).
67 
68         /***************************************************************************************************
69             Another match was found. Increment the count of syms and add the type to our list if it's not
70             already there.
71         ***************************************************************************************************/
RecordType(AggregateType type, Symbol sym)72         private void RecordType(AggregateType type, Symbol sym)
73         {
74             Debug.Assert(type != null && sym != null);
75 
76             if (!_prgtype.Contains(type))
77             {
78                 _prgtype.Add(type);
79             }
80 
81             // Now record the sym....
82 
83             _csym++;
84 
85             // If it is first, record it.
86             if (_swtFirst == null)
87             {
88                 _swtFirst.Set(sym, type);
89                 Debug.Assert(_csym == 1);
90                 Debug.Assert(_prgtype[0] == type);
91                 _fMulti = sym is MethodSymbol || sym is IndexerSymbol;
92             }
93         }
94 
95         /******************************************************************************
96             Search just the given type (not any bases). Returns true iff it finds
97             something (which will have been recorded by RecordType).
98 
99             pfHideByName is set to true iff something was found that hides all
100             members of base types (eg, a hidebyname method).
101         ******************************************************************************/
SearchSingleType(AggregateType typeCur, out bool pfHideByName)102         private bool SearchSingleType(AggregateType typeCur, out bool pfHideByName)
103         {
104             bool fFoundSome = false;
105 
106             pfHideByName = false;
107 
108             // Make sure this type is accessible. It may not be due to private inheritance
109             // or friend assemblies.
110             bool fInaccess = !GetSemanticChecker().CheckTypeAccess(typeCur, _symWhere);
111             if (fInaccess && (_csym != 0 || _swtInaccess != null))
112                 return false;
113 
114             // Loop through symbols.
115             Symbol symCur;
116             for (symCur = GetSymbolLoader().LookupAggMember(_name, typeCur.getAggregate(), symbmask_t.MASK_ALL);
117                  symCur != null;
118                  symCur = SymbolLoader.LookupNextSym(symCur, typeCur.getAggregate(), symbmask_t.MASK_ALL))
119             {
120                 // Check for arity.
121                 switch (symCur.getKind())
122                 {
123                     case SYMKIND.SK_MethodSymbol:
124                         // For non-zero arity, only methods of the correct arity are considered.
125                         // For zero arity, don't filter out any methods since we do type argument
126                         // inferencing.
127                         if (_arity > 0 && ((MethodSymbol)symCur).typeVars.Count != _arity)
128                         {
129                             if (!_swtBadArity)
130                                 _swtBadArity.Set(symCur, typeCur);
131                             continue;
132                         }
133                         break;
134 
135                     case SYMKIND.SK_AggregateSymbol:
136                         // For types, always filter on arity.
137                         if (((AggregateSymbol)symCur).GetTypeVars().Count != _arity)
138                         {
139                             if (!_swtBadArity)
140                                 _swtBadArity.Set(symCur, typeCur);
141                             continue;
142                         }
143                         break;
144 
145                     default:
146                         // All others are only considered when arity is zero.
147                         if (_arity > 0)
148                         {
149                             if (!_swtBadArity)
150                                 _swtBadArity.Set(symCur, typeCur);
151                             continue;
152                         }
153                         break;
154                 }
155 
156                 // Check for user callability.
157                 if (symCur.IsOverride() && !symCur.IsHideByName())
158                 {
159                     continue;
160                 }
161 
162                 MethodOrPropertySymbol methProp = symCur as MethodOrPropertySymbol;
163                 MethodSymbol meth = symCur as MethodSymbol;
164                 if (methProp != null && (_flags & MemLookFlags.UserCallable) != 0 && !methProp.isUserCallable())
165                 {
166                     // If its an indexed property method symbol, let it through.
167                     if (meth != null &&
168                         meth.isPropertyAccessor() &&
169                         ((symCur.name.Text.StartsWith("set_", StringComparison.Ordinal) && meth.Params.Count > 1) ||
170                         (symCur.name.Text.StartsWith("get_", StringComparison.Ordinal) && meth.Params.Count > 0)))
171                     {
172                         if (!_swtInaccess)
173                         {
174                             _swtInaccess.Set(symCur, typeCur);
175                         }
176                         continue;
177                     }
178                 }
179 
180                 if (fInaccess || !GetSemanticChecker().CheckAccess(symCur, typeCur, _symWhere, _typeQual))
181                 {
182                     // Not accessible so get the next sym.
183                     if (!_swtInaccess)
184                     {
185                         _swtInaccess.Set(symCur, typeCur);
186                     }
187                     if (fInaccess)
188                     {
189                         return false;
190                     }
191                     continue;
192                 }
193 
194                 PropertySymbol prop = symCur as PropertySymbol;
195 
196                 // Make sure that whether we're seeing a ctor, operator, or indexer is consistent with the flags.
197                 if (((_flags & MemLookFlags.Ctor) == 0) != (meth == null || !meth.IsConstructor()) ||
198                     ((_flags & MemLookFlags.Operator) == 0) != (meth == null || !meth.isOperator) ||
199                     ((_flags & MemLookFlags.Indexer) == 0) != !(prop is IndexerSymbol))
200                 {
201                     if (!_swtBad)
202                     {
203                         _swtBad.Set(symCur, typeCur);
204                     }
205                     continue;
206                 }
207 
208                 // We can't call CheckBogus on methods or indexers because if the method has the wrong
209                 // number of parameters people don't think they should have to /r the assemblies containing
210                 // the parameter types and they complain about the resulting CS0012 errors.
211                 if (!(symCur is MethodSymbol) && (_flags & MemLookFlags.Indexer) == 0 && CSemanticChecker.CheckBogus(symCur))
212                 {
213                     // A bogus member - we can't use these, so only record them for error reporting.
214                     if (!_swtBogus)
215                     {
216                         _swtBogus.Set(symCur, typeCur);
217                     }
218                     continue;
219                 }
220 
221                 // if we are in a calling context then we should only find a property if it is delegate valued
222                 if ((_flags & MemLookFlags.MustBeInvocable) != 0)
223                 {
224                     if ((symCur is FieldSymbol field && !IsDelegateType(field.GetType(), typeCur) && !IsDynamicMember(symCur)) ||
225                         (prop != null && !IsDelegateType(prop.RetType, typeCur) && !IsDynamicMember(symCur)))
226                     {
227                         if (!_swtBad)
228                         {
229                             _swtBad.Set(symCur, typeCur);
230                         }
231                         continue;
232                     }
233                 }
234 
235                 if (methProp != null)
236                 {
237                     MethPropWithType mwpInsert = new MethPropWithType(methProp, typeCur);
238                     _methPropWithTypeList.Add(mwpInsert);
239                 }
240 
241                 // We have a visible symbol.
242                 fFoundSome = true;
243 
244                 if (_swtFirst)
245                 {
246                     if (!typeCur.isInterfaceType())
247                     {
248                         // Non-interface case.
249                         Debug.Assert(_fMulti || typeCur == _prgtype[0]);
250                         if (!_fMulti)
251                         {
252                             if (_swtFirst.Sym is FieldSymbol && symCur is EventSymbol
253                                 // The isEvent bit is only set on symbols which come from source...
254                                 // This is not a problem for the compiler because the field is only
255                                 // accessible in the scope in which it is declared,
256                                 // but in the EE we ignore accessibility...
257                                 && _swtFirst.Field().isEvent
258                         )
259                             {
260                                 // m_swtFirst is just the field behind the event symCur so ignore symCur.
261                                 continue;
262                             }
263                             else if (_swtFirst.Sym is FieldSymbol && symCur is EventSymbol)
264                             {
265                                 // symCur is the matching event.
266                                 continue;
267                             }
268                             goto LAmbig;
269                         }
270                         if (_swtFirst.Sym.getKind() != symCur.getKind())
271                         {
272                             if (typeCur == _prgtype[0])
273                                 goto LAmbig;
274                             // This one is hidden by the first one. This one also hides any more in base types.
275                             pfHideByName = true;
276                             continue;
277                         }
278                     }
279                     // Interface case.
280                     // m_fMulti   : n n n y y y y y
281                     // same-kind  : * * * y n n n n
282                     // fDiffHidden: * * * * y n n n
283                     // meth       : * * * * * y n *  can n happen? just in case, we better handle it....
284                     // hack       : n * y * * y * n
285                     // meth-2     : * n y * * * * *
286                     // res        : A A S R H H A A
287                     else if (!_fMulti)
288                     {
289                         // Give method groups priority.
290                         if (!(symCur is MethodSymbol))
291                             goto LAmbig;
292                         // Erase previous results so we'll record this method as the first.
293                         _prgtype = new List<AggregateType>();
294                         _csym = 0;
295                         _swtFirst.Clear();
296                         _swtAmbig.Clear();
297                     }
298                     else if (_swtFirst.Sym.getKind() != symCur.getKind())
299                     {
300                         if (!typeCur.fDiffHidden)
301                         {
302                             // Give method groups priority.
303                             if (!(_swtFirst.Sym is MethodSymbol))
304                                 goto LAmbig;
305                         }
306                         // This one is hidden by another. This one also hides any more in base types.
307                         pfHideByName = true;
308                         continue;
309                     }
310                 }
311 
312                 RecordType(typeCur, symCur);
313 
314                 if (methProp != null && methProp.isHideByName)
315                     pfHideByName = true;
316                 // We've found a symbol in this type but need to make sure there aren't any conflicting
317                 // syms here, so keep searching the type.
318             }
319 
320             Debug.Assert(!fInaccess || !fFoundSome);
321 
322             return fFoundSome;
323 
324         LAmbig:
325             // Ambiguous!
326             if (!_swtAmbig)
327                 _swtAmbig.Set(symCur, typeCur);
328             pfHideByName = true;
329             return true;
330         }
331 
IsDynamicMember(Symbol sym)332         private bool IsDynamicMember(Symbol sym)
333         {
334             System.Runtime.CompilerServices.DynamicAttribute da = null;
335             if (sym is FieldSymbol field)
336             {
337                 if (!field.getType().isPredefType(PredefinedType.PT_OBJECT))
338                 {
339                     return false;
340                 }
341                 var o = field.AssociatedFieldInfo.GetCustomAttributes(typeof(System.Runtime.CompilerServices.DynamicAttribute), false).ToArray();
342                 if (o.Length == 1)
343                 {
344                     da = o[0] as System.Runtime.CompilerServices.DynamicAttribute;
345                 }
346             }
347             else
348             {
349                 Debug.Assert(sym is PropertySymbol);
350                 PropertySymbol prop = (PropertySymbol)sym;
351                 if (!prop.getType().isPredefType(PredefinedType.PT_OBJECT))
352                 {
353                     return false;
354                 }
355                 var o = prop.AssociatedPropertyInfo.GetCustomAttributes(typeof(System.Runtime.CompilerServices.DynamicAttribute), false).ToArray();
356                 if (o.Length == 1)
357                 {
358                     da = o[0] as System.Runtime.CompilerServices.DynamicAttribute;
359                 }
360             }
361 
362             if (da == null)
363             {
364                 return false;
365             }
366             return (da.TransformFlags.Count == 0 || (da.TransformFlags.Count == 1 && da.TransformFlags[0]));
367         }
368 
369         /******************************************************************************
370             Lookup in a class and its bases (until *ptypeEnd is hit).
371 
372             ptypeEnd [in/out] - *ptypeEnd should be either null or object. If we find
373                 something here that would hide members of object, this sets *ptypeEnd
374                 to null.
375 
376             Returns true when searching should continue to the interfaces.
377         ******************************************************************************/
LookupInClass(AggregateType typeStart, ref AggregateType ptypeEnd)378         private bool LookupInClass(AggregateType typeStart, ref AggregateType ptypeEnd)
379         {
380             Debug.Assert(!_swtFirst || _fMulti);
381             Debug.Assert(typeStart != null && !typeStart.isInterfaceType() && (ptypeEnd == null || typeStart != ptypeEnd));
382 
383             AggregateType typeEnd = ptypeEnd;
384             AggregateType typeCur;
385 
386             // Loop through types. Loop until we hit typeEnd (object or null).
387             for (typeCur = typeStart; typeCur != typeEnd && typeCur != null; typeCur = typeCur.GetBaseClass())
388             {
389                 Debug.Assert(!typeCur.isInterfaceType());
390 
391                 SearchSingleType(typeCur, out bool fHideByName);
392 
393                 if (_swtFirst && !_fMulti)
394                 {
395                     // Everything below this type and in interfaces is hidden.
396                     return false;
397                 }
398 
399                 if (fHideByName)
400                 {
401                     // This hides everything below it and in object, but not in the interfaces!
402                     ptypeEnd = null;
403 
404                     // Return true to indicate that it's ok to search additional types.
405                     return true;
406                 }
407 
408                 if ((_flags & MemLookFlags.Ctor) != 0)
409                 {
410                     // If we're looking for a constructor, don't check base classes or interfaces.
411                     return false;
412                 }
413             }
414 
415             Debug.Assert(typeCur == typeEnd);
416             return true;
417         }
418 
419         /******************************************************************************
420             Returns true if searching should continue to object.
421         ******************************************************************************/
LookupInInterfaces(AggregateType typeStart, TypeArray types)422         private bool LookupInInterfaces(AggregateType typeStart, TypeArray types)
423         {
424             Debug.Assert(!_swtFirst || _fMulti);
425             Debug.Assert(typeStart == null || typeStart.isInterfaceType());
426             Debug.Assert(typeStart != null || types.Count != 0);
427 
428             // Clear all the hidden flags. Anything found in a class hides any other
429             // kind of member in all the interfaces.
430             if (typeStart != null)
431             {
432                 typeStart.fAllHidden = false;
433                 typeStart.fDiffHidden = (_swtFirst != null);
434             }
435 
436             for (int i = 0; i < types.Count; i++)
437             {
438                 AggregateType type = (AggregateType)types[i];
439                 Debug.Assert(type.isInterfaceType());
440                 type.fAllHidden = false;
441                 type.fDiffHidden = !!_swtFirst;
442             }
443 
444             bool fHideObject = false;
445             AggregateType typeCur = typeStart;
446             int itypeNext = 0;
447 
448             if (typeCur == null)
449             {
450                 typeCur = (AggregateType)types[itypeNext++];
451             }
452             Debug.Assert(typeCur != null);
453 
454             // Loop through the interfaces.
455             for (; ;)
456             {
457                 Debug.Assert(typeCur != null && typeCur.isInterfaceType());
458 
459                 if (!typeCur.fAllHidden && SearchSingleType(typeCur, out bool fHideByName))
460                 {
461                     fHideByName |= !_fMulti;
462 
463                     // Mark base interfaces appropriately.
464                     TypeArray ifaces = typeCur.GetIfacesAll();
465                     for (int i = 0; i < ifaces.Count; i++)
466                     {
467                         AggregateType type = (AggregateType)ifaces[i];
468                         Debug.Assert(type.isInterfaceType());
469                         if (fHideByName)
470                             type.fAllHidden = true;
471                         type.fDiffHidden = true;
472                     }
473 
474                     // If we hide all base types, that includes object!
475                     if (fHideByName)
476                         fHideObject = true;
477                 }
478 
479                 if (itypeNext >= types.Count)
480                     return !fHideObject;
481 
482                 // Substitution has already been done.
483                 typeCur = types[itypeNext++] as AggregateType;
484             }
485         }
486 
GetSymbolLoader()487         private SymbolLoader GetSymbolLoader() { return _pSymbolLoader; }
GetSemanticChecker()488         private CSemanticChecker GetSemanticChecker() { return _pSemanticChecker; }
GetErrorContext()489         private ErrorHandling GetErrorContext() { return GetSymbolLoader().GetErrorContext(); }
490 
ReportBogus(SymWithType swt)491         private RuntimeBinderException ReportBogus(SymWithType swt)
492         {
493             Debug.Assert(CSemanticChecker.CheckBogus(swt.Sym));
494             MethodSymbol meth1 = swt.Prop().GetterMethod;
495             MethodSymbol meth2 = swt.Prop().SetterMethod;
496             Debug.Assert((meth1 ?? meth2) != null);
497             return meth1 == null | meth2 == null
498                 ? GetErrorContext().Error(
499                     ErrorCode.ERR_BindToBogusProp1, swt.Sym.name, new SymWithType(meth1 ?? meth2, swt.GetType()),
500                     new ErrArgRefOnly(swt.Sym))
501                 : GetErrorContext().Error(
502                     ErrorCode.ERR_BindToBogusProp2, swt.Sym.name, new SymWithType(meth1, swt.GetType()),
503                     new SymWithType(meth2, swt.GetType()), new ErrArgRefOnly(swt.Sym));
504         }
505 
IsDelegateType(CType pSrcType, AggregateType pAggType)506         private bool IsDelegateType(CType pSrcType, AggregateType pAggType)
507         {
508             CType pInstantiatedType = GetSymbolLoader().GetTypeManager().SubstType(pSrcType, pAggType, pAggType.GetTypeArgsAll());
509             return pInstantiatedType.isDelegateType();
510         }
511 
512         /////////////////////////////////////////////////////////////////////////////////
513         // Public methods.
514 
MemberLookup()515         public MemberLookup()
516         {
517             _methPropWithTypeList = new List<MethPropWithType>();
518             _rgtypeStart = new List<AggregateType>();
519             _swtFirst = new SymWithType();
520             _swtAmbig = new SymWithType();
521             _swtInaccess = new SymWithType();
522             _swtBad = new SymWithType();
523             _swtBogus = new SymWithType();
524             _swtBadArity = new SymWithType();
525         }
526 
527         /***************************************************************************************************
528             Lookup must be called before anything else can be called.
529 
530             typeSrc - Must be an AggregateType or TypeParameterType.
531             obj - the expression through which the member is being accessed. This is used for accessibility
532                 of protected members and for constructing a MEMGRP from the results of the lookup.
533                 It is legal for obj to be an EK_CLASS, in which case it may be used for accessibility, but
534                 will not be used for MEMGRP construction.
535             symWhere - the symbol from with the name is being accessed (for checking accessibility).
536             name - the name to look for.
537             arity - the number of type args specified. Only members that support this arity are found.
538                 Note that when arity is zero, all methods are considered since we do type argument
539                 inferencing.
540 
541             flags - See MemLookFlags.
542                 TypeVarsAllowed only applies to the most derived type (not base types).
543         ***************************************************************************************************/
Lookup(CSemanticChecker checker, CType typeSrc, Expr obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags)544         public bool Lookup(CSemanticChecker checker, CType typeSrc, Expr obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags)
545         {
546             Debug.Assert((flags & ~MemLookFlags.All) == 0);
547             Debug.Assert(obj == null || obj.Type != null);
548             Debug.Assert(typeSrc is AggregateType);
549             Debug.Assert(checker != null);
550 
551             _prgtype = _rgtypeStart;
552 
553             // Save the inputs for error handling, etc.
554             _pSemanticChecker = checker;
555             _pSymbolLoader = checker.SymbolLoader;
556             _typeSrc = typeSrc;
557             _obj = obj is ExprClass ? null : obj;
558             _symWhere = symWhere;
559             _name = name;
560             _arity = arity;
561             _flags = flags;
562 
563             _typeQual = (_flags & MemLookFlags.Ctor) != 0 ? _typeSrc : obj?.Type;
564 
565             // Determine what to search.
566             AggregateType typeCls1 = null;
567             AggregateType typeIface = null;
568             TypeArray ifaces = BSYMMGR.EmptyTypeArray();
569             AggregateType typeCls2 = null;
570 
571             if (!typeSrc.isInterfaceType())
572             {
573                 typeCls1 = (AggregateType)typeSrc;
574 
575                 if (typeCls1.IsWindowsRuntimeType())
576                 {
577                     ifaces = typeCls1.GetWinRTCollectionIfacesAll(GetSymbolLoader());
578                 }
579             }
580             else
581             {
582                 Debug.Assert(typeSrc.isInterfaceType());
583                 Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0);
584                 typeIface = (AggregateType)typeSrc;
585                 ifaces = typeIface.GetIfacesAll();
586             }
587 
588             if (typeIface != null || ifaces.Count > 0)
589                 typeCls2 = GetSymbolLoader().GetPredefindType(PredefinedType.PT_OBJECT);
590 
591             // Search the class first (except possibly object).
592             if (typeCls1 == null || LookupInClass(typeCls1, ref typeCls2))
593             {
594                 // Search the interfaces.
595                 if ((typeIface != null || ifaces.Count > 0) && LookupInInterfaces(typeIface, ifaces) && typeCls2 != null)
596                 {
597                     // Search object last.
598                     Debug.Assert(typeCls2 != null && typeCls2.isPredefType(PredefinedType.PT_OBJECT));
599 
600                     AggregateType result = null;
601                     LookupInClass(typeCls2, ref result);
602                 }
603             }
604 
605             return !FError();
606         }
607 
608         // Whether there were errors.
FError()609         private bool FError()
610         {
611             return !_swtFirst || _swtAmbig;
612         }
613 
614         // The first symbol found.
SymFirst()615         public Symbol SymFirst()
616         {
617             return _swtFirst.Sym;
618         }
SwtFirst()619         public SymWithType SwtFirst()
620         {
621             return _swtFirst;
622         }
623 
GetObject()624         public Expr GetObject()
625         {
626             return _obj;
627         }
628 
GetSourceType()629         public CType GetSourceType()
630         {
631             return _typeSrc;
632         }
633 
GetFlags()634         public MemLookFlags GetFlags()
635         {
636             return _flags;
637         }
638 
639         // Put all the types in a type array.
GetAllTypes()640         private TypeArray GetAllTypes()
641         {
642             return GetSymbolLoader().getBSymmgr().AllocParams(_prgtype.Count, _prgtype.ToArray());
643         }
644 
645         /******************************************************************************
646             Reports errors. Only call this if FError() is true.
647         ******************************************************************************/
ReportErrors()648         public Exception ReportErrors()
649         {
650             Debug.Assert(FError());
651 
652             // Report error.
653             // NOTE: If the definition of FError changes, this code will need to change.
654             Debug.Assert(!_swtFirst || _swtAmbig);
655 
656             if (_swtFirst)
657             {
658                 // Ambiguous lookup.
659                 return GetErrorContext().Error(ErrorCode.ERR_AmbigMember, _swtFirst, _swtAmbig);
660             }
661 
662             if (_swtInaccess)
663             {
664                 return !_swtInaccess.Sym.isUserCallable() && ((_flags & MemLookFlags.UserCallable) != 0)
665                     ? GetErrorContext().Error(ErrorCode.ERR_CantCallSpecialMethod, _swtInaccess)
666                     : GetSemanticChecker().ReportAccessError(_swtInaccess, _symWhere, _typeQual);
667             }
668 
669             if ((_flags & MemLookFlags.Ctor) != 0)
670             {
671                 return _arity > 0
672                     ? GetErrorContext().Error(ErrorCode.ERR_BadCtorArgCount, _typeSrc.getAggregate(), _arity)
673                     : GetErrorContext().Error(ErrorCode.ERR_NoConstructors, _typeSrc.getAggregate());
674             }
675 
676             if ((_flags & MemLookFlags.Operator) != 0)
677             {
678                 return GetErrorContext().Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
679             }
680 
681             if ((_flags & MemLookFlags.Indexer) != 0)
682             {
683                 return GetErrorContext().Error(ErrorCode.ERR_BadIndexLHS, _typeSrc);
684             }
685 
686             if (_swtBad)
687             {
688                 return GetErrorContext().Error((_flags & MemLookFlags.MustBeInvocable) != 0 ? ErrorCode.ERR_NonInvocableMemberCalled : ErrorCode.ERR_CantCallSpecialMethod, _swtBad);
689             }
690 
691             if (_swtBogus)
692             {
693                 return ReportBogus(_swtBogus);
694             }
695 
696             if (_swtBadArity)
697             {
698                 int cvar;
699 
700                 switch (_swtBadArity.Sym.getKind())
701                 {
702                     case SYMKIND.SK_MethodSymbol:
703                         Debug.Assert(_arity != 0);
704                         cvar = ((MethodSymbol)_swtBadArity.Sym).typeVars.Count;
705                         return GetErrorContext().Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar);
706 
707                     case SYMKIND.SK_AggregateSymbol:
708                         cvar = ((AggregateSymbol)_swtBadArity.Sym).GetTypeVars().Count;
709                         return GetErrorContext().Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar);
710 
711                     default:
712                         Debug.Assert(_arity != 0);
713                         return GetErrorContext().Error(ErrorCode.ERR_TypeArgsNotAllowed, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym));
714                 }
715             }
716 
717             return GetErrorContext().Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
718         }
719     }
720 }
721