📄 typesymbol.cs
字号:
int j;
for(j = i; j < alParamTypes.Length; j++)
{
System.Type tDerived = alParamTypes[j];
string stBase = tBase.ToString();
string stDerived = (tDerived == null) ? "null" : tDerived.ToString();
//if ((tBase != tDerived) && !tDerived.IsSubclassOf(tBase))
if (!SymbolEngine.TypeEntry.IsAssignable(tDerived, tBase))
break;
}
if (j == alParamTypes.Length)
{
info.AddVarargMatch(mDecl);
}
}
} // end vararg
} // end AddIfParamsMatch
// Helper. Lookup the method in the specific scope
// Add all matches to the info object
protected void SearchForOverloadedMethodInScope(
Scope scope,
ISemanticResolver s,
string stName,
System.Type [] alParamTypes,
OverloadedErrorInfo info
)
{
// Find header. If no no header, then the method isn't in this scope
MethodHeaderEntry header = (MethodHeaderEntry) scope.LookupSymbolInThisScopeOnly(m_stMethodHeaderPrefix + stName);
//MethodHeaderEntry header = LookupMethodHeader(stName);
if (header == null)
return;
// Now, traverse list of methods finding an appropriate match
foreach(MethodExpEntry m in header)
{
Debug.Assert(m.Name == stName);
if (m.IsOverride)
continue;
string stDecorated = TypeEntry.GetDecoratedParams(m); // debug helper
AddIfParamsMatch(alParamTypes, m, info);
}
}
// Helper:
// Search for a method in the given class (and all of its super classes)
// Even if we get the method from an interface, it still must be implemented in
// the super-class chain, so just searching that will be sufficient.
// We don't have to search the entire interface tree.
protected void LookupMethodInClass(
ISemanticResolver s,
string stName,
Type [] alParamTypes,
OverloadedErrorInfo info
)
{
Debug.Assert(IsClass || IsStruct || IsRef);
this.EnsureResolved(s);
// Make life really easy be doing a broad search for the method header
// If we don't find that, we won't find any overload / exact match
//MethodHeaderEntry header = (MethodHeaderEntry) m_scope.LookupSymbol(m_stMethodHeaderPrefix + stName);
MethodHeaderEntry header = LookupMethodHeader(stName);
if (header == null)
{
info.SetNoHeader();
return ;
}
string stDecorated = GetDecoratedParams(stName, alParamTypes);
MethodExpEntry sym = null;
// Must resolve a member function (Specified by name & param types) to a symbol.
// A function call may match multiple symbols. Ex:
// class Foo { int f(Base); int f(Derived); }
// Now Foo.f(Derive) technically matches both versions of f; but there's not
// really any ambiguity. So....
// 1) First try for an exact match.
// 2) Else if we don't have an exact match, then we have to do a more
// thorough search based off matching parameter types.
sym = (MethodExpEntry) s.LookupSymbol(m_scope, stDecorated, false);
if (sym != null)
{
info.AddMatch(sym);
return;
}
// @hack - strip all refs and try again...
// @todo - need to properly implement the notion of 'best match'
// because int& --> { int, object }, it should match with object.
{
System.Type [] alParamTypes2 = new System.Type[alParamTypes.Length];
for(int i = 0; i < alParamTypes2.Length; i++)
{
alParamTypes2[i] = alParamTypes[i];
if ((alParamTypes2[i] != null) && alParamTypes2[i].IsByRef)
alParamTypes2[i] = alParamTypes2[i].GetElementType();
}
string stDecorated2 = GetDecoratedParams(stName, alParamTypes2);
sym = (MethodExpEntry) s.LookupSymbol(m_scope, stDecorated2, false);
if (sym != null)
{
info.AddMatch(sym);
return;
}
}
// No exact match found, so do a search:
// Look at each scope in the super-class chain
#if true
Scope oldScope = null;
for(TypeEntry tSearch = this; tSearch != null; tSearch = tSearch.Super)
{
// @todo -major hack. T[] copies scope from System.Array.
// Traversing scopes was ok (since T[]'s --> System.Object, 2 links)
// But traversing by class is not (since T[]'s --> S.Array --> S.Object, 3 links)
// So any array member lookup happens in the same scope twice.
if (oldScope == tSearch.MemberScope)
continue;
oldScope = tSearch.MemberScope;
// In each scope, search all of the methods for a match
SearchForOverloadedMethodInScope(tSearch.MemberScope, s, stName, alParamTypes, info);
}
#else
for(Scope scope = m_scope; scope != null; scope = scope.InheritedParent)
{
// In each scope, search all of the methods for a match
SearchForOverloadedMethodInScope(scope, s, stName, alParamTypes, info);
}
#endif
}
#endregion Internal Lookup helpers
#region Public Lookup functions
// Use for inheritence /debug checks.
// return null if not found.
public MethodExpEntry LookupExactMethod(MethodExpEntry m)
{
string stDecorated = GetDecoratedParams(m);
return (MethodExpEntry) m_scope.LookupSymbol(stDecorated);
}
// Given an undecorated method name, get the header. Used when we want to
// search through a scope by method name and we don't know the parameters
// This is like the inverse of LookupIndexer (in which case we know the
// parameters, but don't know the name)
// Return null if not found.
public MethodHeaderEntry LookupMethodHeader(string stMethodName)
{
MethodHeaderEntry header = (MethodHeaderEntry) m_scope.LookupSymbol(m_stMethodHeaderPrefix + stMethodName);
return header;
}
// Given a method defined in an interface, look it up in the current class
// We search for an exact match.
// Return null if not found.
public MethodExpEntry LookupInterfaceMethod(MethodExpEntry mInterface, bool fLookInSuperClass)
{
Debug.Assert(this.IsClass || this.IsStruct);
Debug.Assert(mInterface.SymbolClass.IsInterface);
string stDecorated = GetDecoratedParams(mInterface);
if (!fLookInSuperClass)
{
SymEntry sym = m_scope.LookupSymbolInThisScopeOnly(stDecorated);
if (sym == null)
return null;
Debug.Assert(sym is MethodExpEntry);
return sym as MethodExpEntry;
}
// Search all class & superclasses for an exact match
//for(Scope scope = m_scope; scope != null; scope = scope.InheritedParent)
for(TypeEntry tSearch = this; tSearch != null; tSearch = tSearch.Super)
{
Scope scope = tSearch.MemberScope;
SymEntry sym = scope.LookupSymbolInThisScopeOnly(stDecorated);
if (sym != null)
{
Debug.Assert(sym is MethodExpEntry);
return sym as MethodExpEntry;
}
}
return null;
}
// Find an indexer. Throw an exception if not found.
// Indexers are recognized by Parameter type & if they're a get/set
public MethodExpEntry LookupIndexer(
FileRange location,
ISemanticResolver s,
Type [] alParamTypes, // includes the value for set_X methods
bool fIsLeft // true for set_X, false for get_X
)
{
OverloadedErrorInfo info = new OverloadedErrorInfo();
// Unfortunately, we don't have the name. We can only match on signature.
for(Scope scope = m_scope; scope != null; scope = scope.m_LexicalParent)
{
// In each scope, search all of the methods for a match
foreach(SymEntry sym in scope)
{
MethodExpEntry m = sym as MethodExpEntry;
if (m != null)
{
// Indexers have special name bit set.
if (m.Info.IsSpecialName && !m.IsCtor)
{
// Still have to discriminate between an indexer & a set property
string stName = m.Name;
if (fIsLeft && !stName.StartsWith("set_"))
continue;
if (!fIsLeft && !stName.StartsWith("get_"))
continue;
this.AddIfParamsMatch(alParamTypes, m, info);
}
}
} // foreach symentry
} // foreach scope
MethodExpEntry mIndexer = info.Symbol;
if (mIndexer == null)
ThrowError(SymbolError.NoAcceptableIndexer(location, alParamTypes, fIsLeft));
Debug.Assert(info.MatchCount == 1, "Ambiguous indexers");
Debug.Assert(!mIndexer.IsCtor); // indexer should not be a ctor
return mIndexer;
}
// Helper to find an overloaded operator.
// Return null if not found.
public MethodExpEntry LookupOverloadedOperator(
ISemanticResolver s,
string stName,
Type [] alParamTypes
)
{
// Overloads just look in classes
OverloadedErrorInfo info = new OverloadedErrorInfo();
if (!IsInterface)
{
LookupMethodInClass(s, stName, alParamTypes, info);
}
return info.Symbol;
}
// General all-purpose method lookup. Good for Class/Interface, overloaded, inherited, etc
// This will delegate out to the proper helpers
//
// Find a method with the given stName that "matches" the given parameter list.
// "matches" means that all arguments at the callsite can be implicitly converted
// to the parameter type at the declaration
//
// Throw exception if method not found.
public MethodExpEntry LookupMethod(
ISemanticResolver s,
Identifier idName,
Type [] alParamTypes,
out bool fIsVarArg
)
{
// Before we lookup anything, make sure we've resolved our scope
this.EnsureResolved(s);
fIsVarArg = false;
string stName = idName.Text;
FileRange location = idName.Location;
//FileRange location = new FileRange();
Debug.Assert(m_scope != null);
Debug.Assert(alParamTypes != null);
string stDecorated = GetDecoratedParams(stName, alParamTypes);
OverloadedErrorInfo info = new OverloadedErrorInfo();
MethodExpEntry sym = null;
// If we're not an interface, then the method must exist in one of our base classes.
// A normal lookup on scope searches base classes, so we're fine.
if (!IsInterface)
{
LookupMethodInClass(s, stName, alParamTypes, info);
}
else
{
// Since classes just have a single base class, we have a simple linear search.
// But since we can implement/inherit many interfaces, we have to search through
// a tree here.
// Do a quick broad seach for the method header. If that's not found, then we'll
// never find the actual method / overload
bool fHeader = LookForMethodHeaderInInterface(stName);
if (!fHeader)
info.SetNoHeader();
else
{
// See if we have a direct match. Must look through entire tree for direct
// match first before searching for overload, else a shallow overload will
// hide an exact-match that's deeper in the tree.
LookupMethodInInterface(s, stDecorated, info);
if (info.MatchCount == 0)
{
// Only do search if we don't have a direct match
SearchForOverloadInInterface(s, stName, alParamTypes, info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -