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