// Copyright Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System;
using System.Diagnostics;
#if FxCop
using InterfaceListMicrosoft.Cci.InterfaceCollection;
using MemberListMicrosoft.Cci.MemberCollection;
using MethodListMicrosoft.Cci.MethodCollection;
using TypeNodeListMicrosoft.Cci.TypeNodeCollection;
using ModuleMicrosoft.Cci.ModuleNode;
using ClassMicrosoft.Cci.ClassNode;
using InterfaceMicrosoft.Cci.InterfaceNode;
#endif
#if CCINamespace
namespace Microsoft.Cci{
#else
namespace System.Compiler
{
#endif
/* Specializer walks an IR, replacing references to type parameters with references to actual types.
* The main complication is that structural types involving type parameters need to be reconstructed.
* Other complications arise from the fact that IL is not orthogonal and requires different instructions
* to be used depending on whether a type is a reference type or a value type. In templates, type parameters
* are treated as reference types when method bodies are generated. In order to instantiate a template with
* a value type argument, it is necessary to walk the method bodies and transform some expressions. This is
* not possible to do in a single pass because method bodies can contain references to signatures defined
* in parts of the IR that have not yet been visited and specialized. Consequently, Specializer ignores
* method bodies.
*
* Once all signatures have been fixed up by Specializer, it is necessary to use MethodBodySpecializer
* to walk the method bodies and fix up the IL to deal with value types that replaced type parameters.
* Another complication to deal with is that MemberBindings and NameBindings can refer to members
* defined in structural types based on type parameters. These must be substituted with references to the
* corresponding members of structural types based on the type arguments. Note that some structural types
* are themselves implemented as templates.
*/
/// <summary>
/// This class specializes a normalized IR by replacing type parameters with type arguments.
/// </summary>
#if !FxCop
public
#endif
class Specializer : StandardVisitor
{
public TypeNodeList pars;
public TypeNodeList args;
public Method CurrentMethod;
public TypeNode CurrentType;
public Module TargetModule;
public Specializer(Module targetModule, TypeNodeList pars, TypeNodeList args)
{
Debug.Assert(pars != null && pars.Count > 0);
Debug.Assert(args != null && args.Count > 0);
this.pars = pars;
this.args = args;
this.TargetModule = targetModule;
}
#if !MinimalReader
public Specializer(Visitor callingVisitor)
: base(callingVisitor)
{
}
public override void TransferStateTo(Visitor targetVisitor)
{
base.TransferStateTo(targetVisitor);
Specializer target = targetVisitor as Specializer;
if (target == null) return;
target.args = this.args;
target.pars = this.pars;
target.CurrentMethod = this.CurrentMethod;
target.CurrentType = this.CurrentType;
}
#endif
public override DelegateNode VisitDelegateNode(DelegateNode delegateNode)
{
return this.VisitTypeNode(delegateNode) as DelegateNode;
}
public override Interface VisitInterfaceReference(Interface Interface)
{
return this.VisitTypeReference(Interface) as Interface;
}
public virtual Member VisitMemberReference(Member member)
{
if (member == null) return null;
#if false && !MinimalReader
ParameterField pField = member as ParameterField;
if (pField != null){
if (pField.Parameter != null) pField.Type = pField.Parameter.Type;
return pField;
}
#endif
TypeNode specializedType = this.VisitTypeReference(member.DeclaringType);
if (specializedType == member.DeclaringType || specializedType == null) return member;
return Specializer.GetCorrespondingMember(member, specializedType);
}
public static Member GetCorrespondingMember(Member/*!*/ member, TypeNode/*!*/ specializedType)
{
//member belongs to a structural type based on a type parameter.
//return the corresponding member from the structural type based on the type argument.
if (member.DeclaringType == null) { Debug.Fail(""); return null; }
MemberList unspecializedMembers = member.DeclaringType.Members;
MemberList specializedMembers = specializedType.Members;
if (unspecializedMembers == null || specializedMembers == null) { Debug.Assert(false); return null; }
int unspecializedOffset = 0;
int specializedOffset = 0;
//The offsets can become > 0 when the unspecialized type and/or specialized type is imported from another assembly
//(and the unspecialized type is in fact a partially specialized type.)
for (int i = 0, n = specializedMembers == null ? 0 : specializedMembers.Count; i < n; i++)
{
Member unspecializedMember = unspecializedMembers[i - unspecializedOffset];
Member specializedMember = specializedMembers[i - specializedOffset];
if (unspecializedMember != null && specializedMember == null && unspecializedOffset == i &&
!(unspecializedMember is TypeParameter || unspecializedMember is ClassParameter))
{
unspecializedOffset++; continue; //Keep current unspecialized member, skip over null specialized member
}
if (unspecializedMember == null && specializedMember != null && specializedOffset == i &&
!(specializedMember is TypeParameter || specializedMember is ClassParameter))
{
specializedOffset++; continue; //Keep current specialized member, skip over null
}
if (unspecializedMember == member)
{
Debug.Assert(specializedMember != null);
return specializedMember;
}
}
Debug.Assert(false);
return null;
}
public readonly Block DummyBody = new Block();
public override Method VisitMethod(Method method)
{
if (method == null) return null;
Method savedCurrentMethod = this.CurrentMethod;
TypeNode savedCurrentType = this.CurrentType;
this.CurrentMethod = method;
this.CurrentType = method.DeclaringType;
method.ThisParameter = (This)this.VisitThis(method.ThisParameter);
method.Attributes = this.VisitAttributeList(method.Attributes);
method.ReturnAttributes = this.VisitAttributeList(method.ReturnAttributes);
method.SecurityAttributes = this.VisitSecurityAttributeList(method.SecurityAttributes);
method.ReturnType = this.VisitTypeReference(method.ReturnType);
#if !MinimalReader
method.ImplementedTypes = this.VisitTypeReferenceList(method.ImplementedTypes);
#endif
method.Parameters = this.VisitParameterList(method.Parameters);
if (TargetPlatform.UseGenerics && this.args != method.TemplateArguments)
{
method.TemplateArguments = this.VisitTypeReferenceList(method.TemplateArguments);
method.TemplateParameters = this.VisitTypeParameterList(method.TemplateParameters);
}
#if ExtendedRuntime
method.Contract = this.VisitMethodContract(method.Contract);
#endif
method.ImplementedInterfaceMethods = this.VisitMethodList(method.ImplementedInterfaceMethods);
this.CurrentMethod = savedCurrentMethod;
this.CurrentType = savedCurrentType;
return method;
}
#if ExtendedRuntime
public override MethodContract VisitMethodContract(MethodContract contract){
if (contract == null) return null;
if (contract.Specializer == null) {
contract.Specializer = new MethodContract.ContractSpecializerDelegate(this.VisitContractPart);
contract.ensures = null;
contract.modifies = null;
contract.requires = null;
} else {
contract.ensures = this.VisitEnsuresList(contract.ensures);
contract.modifies = this.VisitExpressionList(contract.modifies);
contract.requires = this.VisitRequiresList(contract.requires);
}
return contract;
}
private object VisitContractPart(Method method, object part) {
if (method == null) { Debug.Fail("method == null"); return part; }
this.CurrentMethod = method;
this.CurrentType = method.DeclaringType;
EnsuresList es = part as EnsuresList;
if (es != null) return this.VisitEnsuresList(es);
RequiresList rs = part as RequiresList;
if (rs != null) return this.VisitRequiresList(rs);
return part;
}
#endif
public virtual MethodList VisitMethodList(MethodList methods)
{
if (methods == null) return null;
int n = methods.Count;
for (int i = 0; i < n; i++)
methods[i] = (Method)this.VisitMemberReference(methods[i]);
return methods;
}
public override TypeNode VisitTypeNode(TypeNode typeNode)
{
if (typeNode == null) return null;
TypeNode savedCurrentType = this.CurrentType;
if (savedCurrentType != null && savedCurrentType.TemplateArguments != null && savedCurrentType.TemplateArguments.Count > 0 &&
typeNode.Template != null && (typeNode.Template.TemplateParameters == null || typeNode.Template.TemplateParameters.Count == 0))
{
typeNode.TemplateArguments = new TypeNodeList(0);
}
this.CurrentType = typeNode;
typeNode.Attributes = this.VisitAttributeList(typeNode.Attributes);
typeNode.SecurityAttributes = this.VisitSecurityAttributeList(typeNode.SecurityAttributes);
Class c = typeNode as Class;
if (c != null) c.BaseClass = (Class)this.VisitTypeReference(c.BaseClass);
typeNode.Interfaces = this.VisitInterfaceReferenceList(typeNode.Interfaces);
if (typeNode.ProvideTypeMembers != null && typeNode.ProvideNestedTypes != null && typeNode.ProviderHandle != null)
{
typeNode.members = null;
typeNode.ProviderHandle = new SpecializerHandle(typeNode.ProvideNestedTypes, typeNode.ProvideTypeMembers, typeNode.ProviderHandle);
typeNode.ProvideNestedTypes = new TypeNode.NestedTypeProvider(this.ProvideNestedTypes);
typeNode.ProvideTypeMembers = new TypeNode.TypeMemberProvider(this.ProvideTypeMembers);
#if !MinimalReader
DelegateNode delegateNode = typeNode as DelegateNode;
if (delegateNode != null)
{
if (!delegateNode.IsNormalized)
{ //In the Normalized case Parameters are retrieved from the Invoke method, which means evaluating Members
delegateNode.Parameters = this.VisitParameterList(delegateNode.Parameters);
delegateNode.ReturnType = this.VisitTypeReference(delegateNode.ReturnType);
}
}
#endif
}
else
{
typeNode.Members = this.VisitMemberList(typeNode.Members);
DelegateNode delegateNode = typeNode as DelegateNode;
if (delegateNode != null)
{
delegateNode.Parameters = this.VisitParameterList(delegateNode.Parameters);
delegateNode.ReturnType = this.VisitTypeReference(delegateNode.ReturnType);
}
}
this.CurrentType = savedCurrentType;
return typeNode;
}
private void ProvideNestedTypes(TypeNode/*!*/ typeNode, object/*!*/ handle)
{
SpecializerHandle sHandler = (SpecializerHandle)handle;
TypeNode savedCurrentType = this.CurrentType;
this.CurrentType = typeNode;
sHandler.NestedTypeProvider(typeNode, sHandler.Handle);
TypeNodeList nestedTypes = typeNode.nestedTypes;
for (int i = 0, n = nestedTypes == null ? 0 : nestedTypes.Count; i < n; i++)
{
//^ assert nestedTypes != null;
TypeNode nt = nestedTypes[i];
if (nt == null) continue;
this.VisitTypeNode(nt);
}
this.CurrentType = savedCurrentType;
}
private void ProvideTypeMembers(TypeNode/*!*/ typeNode, object/*!*/ handle)
{
SpecializerHandle sHandler = (SpecializerHandle)handle;
TypeNode savedCurrentType = this.CurrentType;
this.CurrentType = typeNode;
sHandler.TypeMemberProvider(typeNode, sHandler.Handle);
typeNode.Members = this.VisitMemberList(typeNode.Members);
DelegateNode delegateNode = typeNode as DelegateNode;
if (delegateNode != null && delegateNode.IsNormalized)
{
delegateNode.Parameters = this.VisitParameterList(delegateNode.Parameters);
delegateNode.ReturnType = this.VisitTypeReference(delegateNode.ReturnType);
}
this.CurrentType = savedCurrentType;
}
internal class SpecializerHandle
{
internal TypeNode.NestedTypeProvider/*!*/ NestedTypeProvider;
internal TypeNode.TypeMemberProvider/*!*/ TypeMemberProvider;
internal object/*!*/ Handle;
internal SpecializerHandle(TypeNode.NestedTypeProvider/*!*/ nestedTypeProvider, TypeNode.TypeMemberProvider/*!*/ typeMemberProvider, object/*!*/ handle)
{
this.NestedTypeProvider = nestedTypeProvider;
this.TypeMemberProvider = typeMemberProvider;
this.Handle = handle;
//^ base();
}
}
public virtual Expression VisitTypeExpression(Expression expr)
{
TypeNodeList pars = this.pars;
TypeNodeList args = this.args;
Identifier id = expr as Identifier;
if (id != null)
{
int key = id.UniqueIdKey;
for (int i = 0, n = pars == null ? 0 : pars.Count, m = args == null ? 0 : args.Count; i < n && i < m; i++)
{
//^ assert pars != null && args != null;
TypeNode par = pars[i];
if (par == null || par.Name == null) continue;
if (par.Name.UniqueIdKey == key) return new Literal(args[i], CoreSystemTypes.Type);
}
return id;
}
#if !MinimalReader
Debug.Assert(expr is QualifiedIdentifier || expr is Literal);
#endif
return expr;
}
public override TypeNode VisitTypeParameter(TypeNode typeParameter)
{
if (typeParameter == null) return null;
if (TargetPlatform.UseGenerics)
{
InterfaceList interfaces = typeParameter.Interfaces;
if (interfaces == null || interfaces.Count == 0) return typeParameter;
TypeNode baseType = this.VisitTypeReference(interfaces[0]);
if (baseType is Interface)
typeParameter.Interfaces = this.VisitInterfaceReferenceList(typeParameter.Interfaces);
else
typeParameter = this.ConvertToClassParameter(baseType, typeParameter);
return typeParameter;
}
else
{
typeParameter.Interfaces = this.VisitInterfaceReferenceList(typeParameter.Interfaces);
return null;
}
}
private TypeNode ConvertToClassParameter(TypeNode baseType, TypeNode/*!*/ typeParameter)
{
ClassParameter result;
if (typeParameter is MethodTypeParameter)
{
result = new MethodClassParameter();
}
else if (typeParameter is TypeParameter)
{
result = new ClassParameter();
result.DeclaringType = typeParameter.DeclaringType;
}
else
return typeParameter; //give up
result.SourceContext = typeParameter.SourceContext;
result.TypeParameterFlags = ((ITypeParameter)typeParameter).TypeParameterFlags;
#if ExtendedRuntime
if (typeParameter.IsUnmanaged) { result.SetIsUnmanaged(); }
#endif
result.Name = typeParameter.Name;
result.Namespace = StandardIds.ClassParameter;
result.BaseClass = baseType is Class ? (Class)baseType : CoreSystemTypes.Object;
result.DeclaringMember = ((ITypeParameter)typeParameter).DeclaringMember;
result.DeclaringModule = typeParameter.DeclaringModule;
result.Flags = typeParameter.Flags & ~TypeFlags.Interface;
//InterfaceList contraints = result.Interfaces = new InterfaceList();
InterfaceList interfaces = typeParameter.Interfaces;
for (int i = 1, n = interfaces == null ? 0 : interfaces.Count; i < n; i++)
{
//^ assert interfaces != null;
interfaces.Add(this.VisitInterfaceReference(interfaces[i]));
}
return result;
}
public override TypeNode VisitTypeReference(TypeNode type)
{ //TODO: break up this method
if (type == null) return null;
TypeNodeList pars = this.pars;
TypeNodeList args = this.args;
switch (type.NodeType)
{
case NodeType.ArrayType:
ArrayType arrType = (ArrayType)type;
TypeNode elemType = this.VisitTypeReference(arrType.ElementType);
if (elemType == arrType.ElementType || elemType == null) return arrType;
if (arrType.IsSzArray()) return elemType.GetArrayType(1);
return elemType.GetArrayType(arrType.Rank, arrType.Sizes, arrType.LowerBounds);
#if !MinimalReader
case NodeType.DelegateNode:
{
FunctionType ftype = type as FunctionType;
if (ftype == null) goto default;
TypeNode referringType = ftype.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(ftype.DeclaringType);
return FunctionType.For(this.VisitTypeReference(ftype.ReturnType), this.VisitParameterList(ftype.Parameters), referringType);
}
#endif
case NodeType.Pointer:
Pointer pType = (Pointer)type;
elemType = this.VisitTypeReference(pType.ElementType);
if (elemType == pType.ElementType || elemType == null) return pType;
return elemType.GetPointerType();
case NodeType.Reference:
Reference rType = (Reference)type;
elemType = this.VisitTypeReference(rType.ElementType);
if (elemType == rType.ElementType || elemType == null) return rType;
return elemType.GetReferenceType();
#if ExtendedRuntime
case NodeType.TupleType:{
TupleType tType = (TupleType)type;
bool reconstruct = false;
MemberList members = tType.Members;
int n = members == null ? 0 : members.Count;
FieldList fields = new FieldList(n);
for (int i = 0; i < n; i++){
//^ assert members != null;
Field f = members[i] as Field;
if (f == null) continue;
f = (Field)f.Clone();
fields.Add(f);
TypeNode oft = f.Type;
TypeNode ft = f.Type = this.VisitTypeReference(f.Type);
if (ft != oft) reconstruct = true;
}
if (!reconstruct) return tType;
TypeNode referringType = tType.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(tType.DeclaringType);
return TupleType.For(fields, referringType);}
case NodeType.TypeIntersection:{
TypeIntersection tIntersect = (TypeIntersection)type;
TypeNode referringType = tIntersect.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(tIntersect.DeclaringType);
return TypeIntersection.For(this.VisitTypeReferenceList(tIntersect.Types), referringType);}
case NodeType.TypeUnion:{
TypeUnion tUnion = (TypeUnion)type;
TypeNode referringType = tUnion.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(tUnion.DeclaringType);
TypeNodeList types = this.VisitTypeReferenceList(tUnion.Types);
if (referringType == null || types == null) { Debug.Fail(""); return null; }
return TypeUnion.For(types, referringType);}
#endif
#if !MinimalReader
case NodeType.ArrayTypeExpression:
ArrayTypeExpression aExpr = (ArrayTypeExpression)type;
aExpr.ElementType = this.VisitTypeReference(aExpr.ElementType);
return aExpr;
case NodeType.BoxedTypeExpression:
BoxedTypeExpression bExpr = (BoxedTypeExpression)type;
bExpr.ElementType = this.VisitTypeReference(bExpr.ElementType);
return bExpr;
case NodeType.ClassExpression:
{
ClassExpression cExpr = (ClassExpression)type;
cExpr.Expression = this.VisitTypeExpression(cExpr.Expression);
Literal lit = cExpr.Expression as Literal; //Could happen if the expression is a template parameter
if (lit != null) return lit.Value as TypeNode;
cExpr.TemplateArguments = this.VisitTypeReferenceList(cExpr.TemplateArguments);
return cExpr;
}
#endif
case NodeType.ClassParameter:
case NodeType.TypeParameter:
int key = type.UniqueKey;
for (int i = 0, n = pars == null ? 0 : pars.Count, m = args == null ? 0 : args.Count; i < n && i < m; i++)
{
//^ assert pars != null && args != null;
TypeNode tp = pars[i];
if (tp == null) continue;
if (tp.UniqueKey == key) return args[i];
if (tp.Name.UniqueIdKey == type.Name.UniqueIdKey && (tp is ClassParameter && type is TypeParameter))
{
//This shouldn't really happen, but in practice it does. Hack past it.
return args[i];
}
}
return type;
#if ExtendedRuntime
case NodeType.ConstrainedType:{
ConstrainedType conType = (ConstrainedType)type;
TypeNode referringType = conType.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(conType.DeclaringType);
TypeNode underlyingType = this.VisitTypeReference(conType.UnderlyingType);
Expression constraint = this.VisitExpression(conType.Constraint);
if (referringType == null || underlyingType == null || constraint == null) { Debug.Fail(""); return null; }
return new ConstrainedType(underlyingType, constraint, referringType);}
#endif
#if !MinimalReader
case NodeType.FlexArrayTypeExpression:
FlexArrayTypeExpression flExpr = (FlexArrayTypeExpression)type;
flExpr.ElementType = this.VisitTypeReference(flExpr.ElementType);
return flExpr;
case NodeType.FunctionTypeExpression:
FunctionTypeExpression ftExpr = (FunctionTypeExpression)type;
ftExpr.Parameters = this.VisitParameterList(ftExpr.Parameters);
ftExpr.ReturnType = this.VisitTypeReference(ftExpr.ReturnType);
return ftExpr;
case NodeType.InvariantTypeExpression:
InvariantTypeExpression invExpr = (InvariantTypeExpression)type;
invExpr.ElementType = this.VisitTypeReference(invExpr.ElementType);
return invExpr;
#endif
case NodeType.InterfaceExpression:
InterfaceExpression iExpr = (InterfaceExpression)type;
if (iExpr.Expression == null) goto default;
iExpr.Expression = this.VisitTypeExpression(iExpr.Expression);
iExpr.TemplateArguments = this.VisitTypeReferenceList(iExpr.TemplateArguments);
return iExpr;
#if !MinimalReader
case NodeType.NonEmptyStreamTypeExpression:
NonEmptyStreamTypeExpression neExpr = (NonEmptyStreamTypeExpression)type;
neExpr.ElementType = this.VisitTypeReference(neExpr.ElementType);
return neExpr;
case NodeType.NonNullTypeExpression:
NonNullTypeExpression nnExpr = (NonNullTypeExpression)type;
nnExpr.ElementType = this.VisitTypeReference(nnExpr.ElementType);
return nnExpr;
case NodeType.NonNullableTypeExpression:
NonNullableTypeExpression nbExpr = (NonNullableTypeExpression)type;
nbExpr.ElementType = this.VisitTypeReference(nbExpr.ElementType);
return nbExpr;
case NodeType.NullableTypeExpression:
NullableTypeExpression nuExpr = (NullableTypeExpression)type;
nuExpr.ElementType = this.VisitTypeReference(nuExpr.ElementType);
return nuExpr;
#endif
case NodeType.OptionalModifier:
{
TypeModifier modType = (TypeModifier)type;
TypeNode modifiedType = this.VisitTypeReference(modType.ModifiedType);
TypeNode modifierType = this.VisitTypeReference(modType.Modifier);
if (modifiedType == null || modifierType == null) { return type; }
#if ExtendedRuntime
if (modifierType != null && modifierType == SystemTypes.NullableType){
if (modifiedType.IsValueType) return modifiedType;
if (TypeNode.HasModifier(modifiedType, SystemTypes.NonNullType))
modifiedType = TypeNode.StripModifier(modifiedType, SystemTypes.NonNullType);
if (modifiedType.IsTemplateParameter) {
return OptionalModifier.For(modifierType, modifiedType);
}
return modifiedType;
}
if (modifierType == SystemTypes.NonNullType) {
if (modifiedType.IsValueType) return modifiedType;
modifiedType = TypeNode.StripModifier(modifiedType, SystemTypes.NonNullType);
}
//^ assert modifiedType != null;
#endif
return OptionalModifier.For(modifierType, modifiedType);
}
case NodeType.RequiredModifier:
{
TypeModifier modType = (TypeModifier)type;
TypeNode modifiedType = this.VisitTypeReference(modType.ModifiedType);
TypeNode modifierType = this.VisitTypeReference(modType.Modifier);
if (modifiedType == null || modifierType == null) { Debug.Fail(""); return type; }
return RequiredModifier.For(modifierType, modifiedType);
}
#if !MinimalReader
case NodeType.OptionalModifierTypeExpression:
OptionalModifierTypeExpression optmodType = (OptionalModifierTypeExpression)type;
optmodType.ModifiedType = this.VisitTypeReference(optmodType.ModifiedType);
optmodType.Modifier = this.VisitTypeReference(optmodType.Modifier);
return optmodType;
case NodeType.RequiredModifierTypeExpression:
RequiredModifierTypeExpression reqmodType = (RequiredModifierTypeExpression)type;
reqmodType.ModifiedType = this.VisitTypeReference(reqmodType.ModifiedType);
reqmodType.Modifier = this.VisitTypeReference(reqmodType.Modifier);
return reqmodType;
case NodeType.PointerTypeExpression:
PointerTypeExpression pExpr = (PointerTypeExpression)type;
pExpr.ElementType = this.VisitTypeReference(pExpr.ElementType);
return pExpr;
case NodeType.ReferenceTypeExpression:
ReferenceTypeExpression rExpr = (ReferenceTypeExpression)type;
rExpr.ElementType = this.VisitTypeReference(rExpr.ElementType);
return rExpr;
case NodeType.StreamTypeExpression:
StreamTypeExpression sExpr = (StreamTypeExpression)type;
sExpr.ElementType = this.VisitTypeReference(sExpr.ElementType);
return sExpr;
case NodeType.TupleTypeExpression:
TupleTypeExpression tuExpr = (TupleTypeExpression)type;
tuExpr.Domains = this.VisitFieldList(tuExpr.Domains);
return tuExpr;
case NodeType.TypeExpression:
{
TypeExpression tExpr = (TypeExpression)type;
tExpr.Expression = this.VisitTypeExpression(tExpr.Expression);
if (tExpr.Expression is Literal) return type;
tExpr.TemplateArguments = this.VisitTypeReferenceList(tExpr.TemplateArguments);
return tExpr;
}
case NodeType.TypeIntersectionExpression:
TypeIntersectionExpression tiExpr = (TypeIntersectionExpression)type;
tiExpr.Types = this.VisitTypeReferenceList(tiExpr.Types);
return tiExpr;
case NodeType.TypeUnionExpression:
TypeUnionExpression tyuExpr = (TypeUnionExpression)type;
tyuExpr.Types = this.VisitTypeReferenceList(tyuExpr.Types);
return tyuExpr;
#endif
default:
TypeNode declaringType = this.VisitTypeReference(type.DeclaringType);
if (declaringType != null)
{
Identifier tname = type.Name;
if (type.Template != null && type.IsGeneric) tname = type.Template.Name;
TypeNode nt = declaringType.GetNestedType(tname);
if (nt != null)
{
TypeNodeList arguments = type.TemplateArguments;
type = nt;
if (TargetPlatform.UseGenerics)
{
if (arguments != null && arguments.Count > 0 && nt.ConsolidatedTemplateParameters != null && nt.ConsolidatedTemplateParameters.Count > 0)
type = nt.GetTemplateInstance(this.TargetModule, this.CurrentType, declaringType, arguments);
}
}
}
if (type.Template != null && (type.ConsolidatedTemplateParameters == null || type.ConsolidatedTemplateParameters.Count == 0))
{
if (!type.IsNotFullySpecialized && (!type.IsNormalized ||
(this.CurrentType != null && type.DeclaringModule == this.CurrentType.DeclaringModule))) return type;
//Type is a template instance, but some of its arguments were themselves parameters.
//See if any of these parameters are to be specialized by this specializer.
bool mustSpecializeFurther = false;
TypeNodeList targs = type.TemplateArguments;
int numArgs = targs == null ? 0 : targs.Count;
if (targs != null)
{
targs = targs.Clone();
for (int i = 0; i < numArgs; i++)
{
TypeNode targ = targs[i];
ITypeParameter tparg = targ as ITypeParameter;
if (tparg != null)
{
for (int j = 0, np = pars == null ? 0 : pars.Count, m = args == null ? 0 : args.Count; j < np && j < m; j++)
{
//^ assert pars != null && args != null;
if (TargetPlatform.UseGenerics)
{
ITypeParameter par = pars[j] as ITypeParameter;
if (par == null) continue;
if (tparg == par || (tparg.ParameterListIndex == par.ParameterListIndex && tparg.DeclaringMember == par.DeclaringMember))
{
targ = this.args[j]; break;
}
}
else
{
if (targ == pars[j]) { targ = this.args[j]; break; }
}
}
}
else
{
if (targ != type)
targ = this.VisitTypeReference(targ);
if (targ == type) continue;
}
mustSpecializeFurther |= targs[i] != targ;
targs[i] = targ;
}
}
if (targs == null || !mustSpecializeFurther) return type;
return type.Template.GetTemplateInstance(this.TargetModule, this.CurrentType, declaringType, targs);
}
TypeNodeList tPars = type.TemplateParameters;
if (tPars == null || tPars.Count == 0) return type; //Not a parameterized type. No need to get an instance.
TypeNodeList tArgs = new TypeNodeList();
for (int i = 0, n = tPars.Count; i < n; i++)
{
TypeNode tPar = tPars[i];
tArgs.Add(tPar); //Leave parameter in place if there is no match
if (tPar == null || tPar.Name == null) continue;
int idKey = tPar.Name.UniqueIdKey;
for (int j = 0, m = pars == null ? 0 : pars.Count, k = args == null ? 0 : args.Count; j < m && j < k; j++)
{
//^ assert pars != null && args != null;
TypeNode par = pars[j];
if (par == null || par.Name == null) continue;
if (par.Name.UniqueIdKey == idKey)
{
tArgs[i] = args[j];
break;
}
}
}
return type.GetTemplateInstance(this.TargetModule, this.CurrentType, this.VisitTypeReference(type.DeclaringType), tArgs);
}
}
}
#if !NoWriter
public class MethodBodySpecializer : Specializer
{
public TrivialHashtable/*!*/ alreadyVisitedNodes = new TrivialHashtable();
public Method methodBeingSpecialized;
public Method dummyMethod;
public MethodBodySpecializer(Module module, TypeNodeList pars, TypeNodeList args)
: base(module, pars, args)
{
//^ base;
}
#if !MinimalReader
public MethodBodySpecializer(Visitor callingVisitor)
: base(callingVisitor)
{
//^ base;
}
#endif
public override Node Visit(Node node)
{
Literal lit = node as Literal;
if (lit != null && lit.Value == null) return lit;
Expression e = node as Expression;
if (e != null && !(e is Local || e is Parameter))
e.Type = this.VisitTypeReference(e.Type);
return base.Visit(node);
}
public override Expression VisitAddressDereference(AddressDereference addr)
{
if (addr == null) return null;
bool unboxDeref = addr.Address != null && addr.Address.NodeType == NodeType.Unbox;
addr.Address = this.VisitExpression(addr.Address);
if (addr.Address == null) return null;
if (unboxDeref && addr.Address.NodeType != NodeType.Unbox) return addr.Address;
Reference reference = addr.Address.Type as Reference;
if (reference != null) addr.Type = reference.ElementType;
return addr;
}
public override Statement VisitAssignmentStatement(AssignmentStatement assignment)
{
assignment = (AssignmentStatement)base.VisitAssignmentStatement(assignment);
if (assignment == null) return null;
Expression target = assignment.Target;
Expression source = assignment.Source;
TypeNode tType = target == null ? null : target.Type;
TypeNode sType = source == null ? null : source.Type;
if (tType != null && sType != null)
{
//^ assert target != null;
if (tType.IsValueType)
{
if (sType is Reference)
assignment.Source = new AddressDereference(source, tType);
else if (!sType.IsValueType && !(sType == CoreSystemTypes.Object && source is Literal && target.NodeType == NodeType.AddressDereference))
assignment.Source = new AddressDereference(new BinaryExpression(source, new MemberBinding(null, sType), NodeType.Unbox), sType);
}
else
{
if (sType.IsValueType)
{
if (!(tType is Reference))
assignment.Source = new BinaryExpression(source, new MemberBinding(null, sType), NodeType.Box, tType);
}
}
}
return assignment;
}
public override Expression VisitBinaryExpression(BinaryExpression binaryExpression)
{
if (binaryExpression == null) return null;
bool opnd1IsInst = binaryExpression.Operand1 != null && binaryExpression.Operand1.NodeType == NodeType.Isinst;
binaryExpression = (BinaryExpression)base.VisitBinaryExpression(binaryExpression);
if (binaryExpression == null) return null;
Expression opnd1 = binaryExpression.Operand1;
Expression opnd2 = binaryExpression.Operand2;
Literal lit = opnd2 as Literal;
TypeNode t = lit == null ? null : lit.Value as TypeNode;
if (binaryExpression.NodeType == NodeType.Castclass /*|| binaryExpression.NodeType == NodeType.ExplicitCoercion*/)
{
//See if castclass must become box or unbox
if (t != null)
{
if (t.IsValueType)
{
AddressDereference adref = new AddressDereference(new BinaryExpression(opnd1, lit, NodeType.Unbox), t);
adref.Type = t;
return adref;
}
if (opnd1 != null && opnd1.Type != null && opnd1.Type.IsValueType)
{
return new BinaryExpression(opnd1, new MemberBinding(null, opnd1.Type), NodeType.Box, t);
}
}
}
else if (binaryExpression.NodeType == NodeType.Unbox)
{
if (opnd1 != null && opnd1.Type != null && opnd1.Type.IsValueType)
return opnd1;
#if ExtendedRuntime
}else if (binaryExpression.NodeType == NodeType.Box){
if (t != null && t.IsReferenceType && !t.IsPointerType) { // using pointer types is a Sing# extension
return opnd1;
}
#endif
}
else if (binaryExpression.NodeType == NodeType.Eq)
{
//For value types, turn comparisons against null into false
if (lit != null && lit.Value == null && opnd1 != null && opnd1.Type != null && opnd1.Type.IsValueType)
return Literal.False;
lit = opnd1 as Literal;
if (lit != null && lit.Value == null && opnd2 != null && opnd2.Type != null && opnd2.Type.IsValueType)
return Literal.False;
}
else if (binaryExpression.NodeType == NodeType.Ne)
{
//For value types, turn comparisons against null into true
if (lit != null && lit.Value == null && opnd1 != null && opnd1.Type != null && opnd1.Type.IsValueType)
{
if (opnd1IsInst && opnd1.Type == CoreSystemTypes.Boolean) return opnd1;
return Literal.True;
}
lit = opnd1 as Literal;
if (lit != null && lit.Value == null && opnd2 != null && opnd2.Type != null && opnd2.Type.IsValueType)
return Literal.True;
}
else if (binaryExpression.NodeType == NodeType.Isinst)
{
//Do not emit isinst instruction if opnd1 is a value type.
if (opnd1 != null && opnd1.Type != null && opnd1.Type.IsValueType)
{
if (opnd1.Type == t)
return Literal.True;
else
return Literal.False;
}
}
return binaryExpression;
}
public override Statement VisitBranch(Branch branch)
{
branch = (Branch)base.VisitBranch(branch);
if (branch == null) return null;
if (branch.Condition != null && !(branch.Condition is BinaryExpression))
{
//Deal with implicit comparisons against null
TypeNode ct = branch.Condition.Type;
if (ct != null && !ct.IsPrimitiveInteger && ct != CoreSystemTypes.Boolean && ct.IsValueType)
{
if (branch.Condition.NodeType == NodeType.LogicalNot)
return null;
branch.Condition = null;
}
}
return branch;
}
public override Expression VisitExpression(Expression expression)
{
if (expression == null) return null;
switch (expression.NodeType)
{
case NodeType.Dup:
case NodeType.Arglist:
expression.Type = this.VisitTypeReference(expression.Type);
return expression;
case NodeType.Pop:
expression.Type = this.VisitTypeReference(expression.Type);
UnaryExpression uex = expression as UnaryExpression;
if (uex != null)
{
uex.Operand = this.VisitExpression(uex.Operand);
return uex;
}
return expression;
default:
return (Expression)this.Visit(expression);
}
}
public override Expression VisitIndexer(Indexer indexer)
{
indexer = (Indexer)base.VisitIndexer(indexer);
if (indexer == null || indexer.Object == null) return null;
ArrayType arrType = indexer.Object.Type as ArrayType;
TypeNode elemType = null;
if (arrType != null) elemType = indexer.Type = indexer.ElementType = arrType.ElementType;
//if (elemType != null && elemType.IsValueType && !elemType.IsPrimitive)
//return new AddressDereference(new UnaryExpression(indexer, NodeType.AddressOf), elemType);
return indexer;
}
public override Expression VisitLiteral(Literal literal)
{
if (literal == null) return null;
TypeNode t = literal.Value as TypeNode;
if (t != null && literal.Type == CoreSystemTypes.Type)
return new Literal(this.VisitTypeReference(t), literal.Type, literal.SourceContext);
return (Literal)literal.Clone();
}
public override Expression VisitLocal(Local local)
{
if (local == null) return null;
if (this.alreadyVisitedNodes[local.UniqueKey] != null) return local;
this.alreadyVisitedNodes[local.UniqueKey] = local;
return base.VisitLocal(local);
}
#if !MinimalReader
public override Statement VisitLocalDeclarationsStatement(LocalDeclarationsStatement localDeclarations)
{
if (localDeclarations == null) return null;
localDeclarations.Type = this.VisitTypeReference(localDeclarations.Type);
return localDeclarations;
}
#endif
public override Expression VisitParameter(Parameter parameter)
{
#if !MinimalReader
ParameterBinding pb = parameter as ParameterBinding;
if (pb != null && pb.BoundParameter != null)
pb.Type = pb.BoundParameter.Type;
#endif
return parameter;
}
#if !MinimalReader
public override Expression VisitNameBinding(NameBinding nameBinding)
{
if (nameBinding == null) return null;
nameBinding.BoundMember = this.VisitExpression(nameBinding.BoundMember);
int n = nameBinding.BoundMembers == null ? 0 : nameBinding.BoundMembers.Count;
for (int i = 0; i < n; i++)
{
//^ assert nameBinding.BoundMembers != null;
nameBinding.BoundMembers[i] = this.VisitMemberReference(nameBinding.BoundMembers[i]);
}
return nameBinding;
}
#endif
public override Expression VisitMemberBinding(MemberBinding memberBinding)
{
if (memberBinding == null) return null;
Expression tObj = memberBinding.TargetObject = this.VisitExpression(memberBinding.TargetObject);
Member mem = this.VisitMemberReference(memberBinding.BoundMember);
if (mem == this.dummyMethod)
mem = this.methodBeingSpecialized;
Debug.Assert(mem != null);
memberBinding.BoundMember = mem;
if (memberBinding == null) return null;
Method method = memberBinding.BoundMember as Method;
if (method != null)
{
//Need to take the address of the target object (this parameter), or need to box it, if this target object type is value type
if (tObj != null && tObj.Type != null && tObj.Type.IsValueType)
{
if (tObj.NodeType != NodeType.This)
{
if (method.DeclaringType != null && method.DeclaringType.IsValueType) //it expects the address of the value type
memberBinding.TargetObject = new UnaryExpression(memberBinding.TargetObject, NodeType.AddressOf, memberBinding.TargetObject.Type.GetReferenceType());
else
{ //it expects a boxed copy of the value type
MemberBinding obType = new MemberBinding(null, memberBinding.TargetObject.Type);
memberBinding.TargetObject = new BinaryExpression(memberBinding.TargetObject, obType, NodeType.Box, method.DeclaringType);
}
}
else
{
//REVIEW: perhaps This nodes of value types should be explicitly typed as reference types
//TODO: assert false in that case
}
}
}
return memberBinding;
}
public override Method VisitMethod(Method method)
{
if (method == null) return null;
Method savedCurrentMethod = this.CurrentMethod;
TypeNode savedCurrentType = this.CurrentType;
this.CurrentMethod = method;
this.CurrentType = method.DeclaringType;
method.Body = this.VisitBlock(method.Body);
this.CurrentMethod = savedCurrentMethod;
this.CurrentType = savedCurrentType;
return method;
}
public override Expression VisitConstruct(Construct cons)
{
cons = (Construct)base.VisitConstruct(cons);
if (cons == null) return null;
MemberBinding mb = cons.Constructor as MemberBinding;
if (mb == null) return cons;
Method meth = mb.BoundMember as Method;
if (meth == null) return cons;
ParameterList parameters = meth.Parameters;
if (parameters == null) return cons;
ExpressionList operands = cons.Operands;
int n = operands == null ? 0 : operands.Count;
if (n > parameters.Count) n = parameters.Count;
for (int i = 0; i < n; i++)
{
//^ assert operands != null;
Expression e = operands[i];
if (e == null) continue;
Parameter p = parameters[i];
if (p == null) continue;
if (e.Type == null || p.Type == null) continue;
if (e.Type.IsValueType && !p.Type.IsValueType)
operands[i] = new BinaryExpression(e, new MemberBinding(null, e.Type), NodeType.Box, p.Type);
}
return cons;
}
public override Expression VisitMethodCall(MethodCall call)
{
call = (MethodCall)base.VisitMethodCall(call);
if (call == null) return null;
MemberBinding mb = call.Callee as MemberBinding;
if (mb == null) return call;
Method meth = mb.BoundMember as Method;
if (meth == null) return call;
ParameterList parameters = meth.Parameters;
if (parameters == null) return call;
ExpressionList operands = call.Operands;
int n = operands == null ? 0 : operands.Count;
if (n > parameters.Count) n = parameters.Count;
for (int i = 0; i < n; i++)
{
//^ assert operands != null;
Expression e = operands[i];
if (e == null) continue;
Parameter p = parameters[i];
if (p == null) continue;
if (e.Type == null || p.Type == null) continue;
if (e.Type.IsValueType && !p.Type.IsValueType)
operands[i] = new BinaryExpression(e, new MemberBinding(null, e.Type), NodeType.Box, p.Type);
}
if (meth.ReturnType != null && call.Type != null && meth.ReturnType.IsValueType && !call.Type.IsValueType)
return new BinaryExpression(call, new MemberBinding(null, meth.ReturnType), NodeType.Box, call.Type);
return call;
}
public override Statement VisitReturn(Return Return)
{
Return = (Return)base.VisitReturn(Return);
if (Return == null) return null;
Expression rval = Return.Expression;
if (rval == null || rval.Type == null || this.CurrentMethod == null || this.CurrentMethod.ReturnType == null)
return Return;
if (rval.Type.IsValueType && !this.CurrentMethod.ReturnType.IsValueType)
Return.Expression = new BinaryExpression(rval, new MemberBinding(null, rval.Type), NodeType.Box, this.CurrentMethod.ReturnType);
return Return;
}
public override TypeNode VisitTypeNode(TypeNode typeNode)
{
if (typeNode == null) return null;
TypeNode savedCurrentType = this.CurrentType;
this.CurrentType = typeNode;
MemberList members = typeNode.Members;
for (int i = 0, n = members == null ? 0 : members.Count; i < n; i++)
{
//^ assert members != null;
Member mem = members[i];
TypeNode t = mem as TypeNode;
if (t != null) { this.VisitTypeNode(t); continue; }
Method m = mem as Method;
if (m != null) { this.VisitMethod(m); continue; }
}
this.CurrentType = savedCurrentType;
return typeNode;
}
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression)
{
if (unaryExpression == null) return null;
return base.VisitUnaryExpression((UnaryExpression)unaryExpression.Clone());
}
}
#endif
}
|