private CType LoadSymbolsFromType(Type originalType)
{
List<object> declarationChain = BuildDeclarationChain(originalType);
Type type = originalType;
CType ret = null;
bool bIsByRef = type.IsByRef;
if (bIsByRef)
{
type = type.GetElementType();
}
NamespaceOrAggregateSymbol current = _rootNamespace;
// Go through the declaration chain and add namespaces and types for
// each element in the chain.
for (int i = 0; i < declarationChain.Count; i++)
{
object o = declarationChain[i];
NamespaceOrAggregateSymbol next;
if (o is Type)
{
Type t = o as Type;
Name name = null;
name = GetName(t);
next = _symbolTable.LookupSym(name, current, symbmask_t.MASK_AggregateSymbol).AsAggregateSymbol();
// Make sure we match arity as well when we find an aggregate.
if (next != null)
{
next = FindSymWithMatchingArity(next as AggregateSymbol, t);
}
// In the event that two different types exist that have the same name, they
// cannot both have entries in the symbol table with our current architecture.
// This can happen in dynamic, since the runtime binder lives across all
// call sites in an appdomain, and assemblies can have been loaded at runtime
// that have different types with the same name.
// In the real compiler, this would have been an error and name lookup would
// be ambiguous, but here we never have to lookup names of types for real (only
// names of members).
// The tactical fix is this: if we encounter this situation, where we have
// identically named types that are not the same, then we are going to clear
// the entire symbol table and restart this binding. This solution is not
// without its own problems, since it is possible to conceive of a single
// dynamic binding that needs to simultaneously know about both of the
// similarly named types, but we are not going to try to solve that
// scenario here.
if (next != null && next is AggregateSymbol)
{
Type existingType = (next as AggregateSymbol).AssociatedSystemType;
Type newType = t.GetTypeInfo().IsGenericType ? t.GetTypeInfo().GetGenericTypeDefinition() : t;
// We use "IsEquivalentTo" so that unified local types for NoPIA do
// not trigger a reset. There are other mechanisms to make those sorts
// of types work in some scenarios.
if (!existingType.IsEquivalentTo(newType))
{
throw new ResetBindException();
}
}
// If we haven't found this type yet, then add it to our symbol table.
if (next == null || t.IsNullableType())
{
// Note that if we have anything other than an AggregateSymbol,
// we must be at the end of the line - that is, nothing else can
// have children.
CType ctype = ProcessSpecialTypeInChain(current, t);
if (ctype != null)
{
// If we had an aggregate type, its possible we're not at the end.
// This will happen for nullable<T> for instance.
if (ctype.IsAggregateType())
{
next = ctype.AsAggregateType().GetOwningAggregate();
}
else
{
ret = ctype;
break;
}
}
else
{
// This is a regular class.
next = AddAggregateToSymbolTable(current, t);
}
}
if (t == type)
{
ret = GetConstructedType(type, next.AsAggregateSymbol());
break;
}
}
else if (o is MethodInfo)
{
// We cant be at the end.
Debug.Assert(i + 1 < declarationChain.Count);
ret = ProcessMethodTypeParameter(o as MethodInfo, declarationChain[++i] as Type, current as AggregateSymbol);
break;
}
else
{
Debug.Assert(o is string);
next = AddNamespaceToSymbolTable(current, o as string);
}
current = next;
}
Debug.Assert(ret != null);
if (bIsByRef)
{
ret = _typeManager.GetParameterModifier(ret, false);
}
return ret;
}