summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/CCI/Specializer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/CCI/Specializer.cs')
-rw-r--r--tools/Sandcastle/Source/CCI/Specializer.cs1054
1 files changed, 1054 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/CCI/Specializer.cs b/tools/Sandcastle/Source/CCI/Specializer.cs
new file mode 100644
index 0000000..d651883
--- /dev/null
+++ b/tools/Sandcastle/Source/CCI/Specializer.cs
@@ -0,0 +1,1054 @@
+// 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 InterfaceList = Microsoft.Cci.InterfaceCollection;
+using MemberList = Microsoft.Cci.MemberCollection;
+using MethodList = Microsoft.Cci.MethodCollection;
+using TypeNodeList = Microsoft.Cci.TypeNodeCollection;
+using Module = Microsoft.Cci.ModuleNode;
+using Class = Microsoft.Cci.ClassNode;
+using Interface = Microsoft.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
+}