internal override InvalidInfo CheckValid(ValidityContext vctxt, MessageContext ctxt, RootEnvironment rootEnv) { var v = base.CheckValid(vctxt, ctxt, rootEnv); if (v != null) { return(v); } var typeEnv = DefiningType.Enter(rootEnv); var methodDef = typeEnv.Type.ResolveMethod(signature); if (methodDef == null) { vctxt.Log(new InvalidMemberRef(ctxt, this, "No such method in defining type")); return(new InvalidInfo(MessageContextBuilders.Member(vctxt.Global, this))); } var methEnv = typeEnv.AddMethod(methodDef).AddSelfMethodBoundArguments(); v = signature.CheckValid(vctxt, ctxt, methEnv); if (v != null) { return(v); } return(vctxt.ImplementableMemberRef(ctxt, rootEnv, this)); }
internal override void AccumUsedTypeAndMemberDefs(ValidityContext vctxt, AssemblyDef assemblyDef, TypeDef typeDef) { base.AccumUsedTypeAndMemberDefs(vctxt, assemblyDef, typeDef); var ctxt = MessageContextBuilders.Member(vctxt.Global, assemblyDef, typeDef, this); Invalid = FieldType.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); }
// // Validity // internal virtual InvalidInfo AccumUsedTypeDefs(ValidityContext vctxt, MessageContext ctxt, Set <QualifiedTypeName> usedTypes) { var v = DefiningType.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (v != null) { return(v); } v = Signature.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (v != null) { return(v); } var assemblyDef = default(AssemblyDef); var typeDef = default(TypeDef); if (DefiningType.PrimTryResolve(vctxt.Global, out assemblyDef, out typeDef)) { if (!typeDef.HasMember(Signature)) { vctxt.Log (new InvalidMemberRef (ctxt, this, "Defining type does not contain definition for matching member")); return(new InvalidInfo(MessageContextBuilders.Member(vctxt.Global, this))); } } return(null); }
internal void PropogateInvalidity(Global global, AssemblyDef assemblyDef, TypeDef typeDef) { if (Invalid == null) { return; } if (usedByMembers != null) { var self = PrimReference(global, assemblyDef, typeDef, null); foreach (var r in usedByMembers) { var usedByAssemblyDef = default(AssemblyDef); var usedByTypeDef = default(TypeDef); var usedByMemberDef = default(MemberDef); if (r.PrimTryResolve(global, out usedByAssemblyDef, out usedByTypeDef, out usedByMemberDef)) { if (usedByMemberDef.Invalid == null) { usedByMemberDef.Invalid = new InvalidInfo(MessageContextBuilders.Member(global, self), Invalid); } } } } }
internal override void CheckValid(ValidityContext vctxt, TypeEnvironment typeEnv) { if (Invalid != null || typeEnv.Type.Invalid != null) { return; } var ctxt = MessageContextBuilders.Member(vctxt.Global, typeEnv.Assembly, typeEnv.Type, this); if (Get != null) { Invalid = Get.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { return; } } if (Set != null) { Invalid = Set.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { return; } } Invalid = FieldType.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { vctxt.ImplementableMemberDef(typeEnv.Assembly, typeEnv.Type, this); } }
internal override void CheckValid(ValidityContext vctxt, TypeEnvironment typeEnv) { if (Invalid != null || typeEnv.Type.Invalid != null) { return; } var ctxt = MessageContextBuilders.Member(vctxt.Global, typeEnv.Assembly, typeEnv.Type, this); if (Add != null) { Invalid = Add.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { return; } } if (Remove != null) { Invalid = Remove.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { return; } } Invalid = HandlerType.CheckValid(vctxt, ctxt, typeEnv); if (Invalid != null) { return; } vctxt.ImplementableMemberDef(typeEnv.Assembly, typeEnv.Type, this); }
internal override void AccumUsedTypeAndMemberDefs(ValidityContext vctxt, AssemblyDef assemblyDef, TypeDef typeDef) { base.AccumUsedTypeAndMemberDefs(vctxt, assemblyDef, typeDef); var ctxt = MessageContextBuilders.Member(vctxt.Global, assemblyDef, typeDef, this); for (var i = 0; i < TypeParameters.Count; i++) { var p = TypeParameters[i]; p.AccumUsedTypeDefs(vctxt, assemblyDef, false); if (p.Invalid != null) { Invalid = new InvalidInfo(MessageContextBuilders.TypeArg(ParameterFlavor.Method, i), p.Invalid); return; } } foreach (var p in ValueParameters) { Invalid = p.Type.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } if (Result != null) { Invalid = Result.Type.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } if (vctxt.IgnoreMethodDefBody(assemblyDef, typeDef, this)) { return; } foreach (var l in Locals) { Invalid = l.Type.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } var instructions = Instructions(vctxt.Global); if (instructions != null) { foreach (var i in instructions.Body) { Invalid = i.AccumUsedTypeAndMemberDefs(vctxt, ctxt, usedTypes, usedMembers); if (Invalid != null) { return; } } } }
internal override InvalidInfo CheckValid(ValidityContext vctxt, MessageContext ctxt, RootEnvironment rootEnv) { var v = base.CheckValid(vctxt, ctxt, rootEnv); if (v != null) { return(v); } if (MethodTypeArguments.Count != MethodTypeArity) { vctxt.Log (new InvalidMemberRef (ctxt, this, String.Format ("Polymorphic method has {0} type parameters but is applied to {1} type arguments", MethodTypeArity, MethodTypeArguments.Count))); return(new InvalidInfo(MessageContextBuilders.Member(vctxt.Global, this))); } v = MethodTypeArguments.Select(t => t.CheckValid(vctxt, ctxt, rootEnv)).FirstOrDefault(v2 => v2 != null); if (v != null) { return(v); } var groundMethodTypeArguments = rootEnv.SubstituteTypes(MethodTypeArguments); var typeEnv = DefiningType.Enter(rootEnv); var methodDef = typeEnv.Type.ResolveMethod(signature); if (methodDef == null) { throw new InvalidOperationException("unable to resolve method"); } var methEnv = typeEnv.AddMethod(methodDef).AddMethodBoundArguments(groundMethodTypeArguments); return(signature.CheckValid(vctxt, ctxt, methEnv)); }
internal override void AccumUsedTypeAndMemberDefs(ValidityContext vctxt, AssemblyDef assemblyDef, TypeDef typeDef) { base.AccumUsedTypeAndMemberDefs(vctxt, assemblyDef, typeDef); var ctxt = MessageContextBuilders.Member(vctxt.Global, assemblyDef, typeDef, this); if (Get != null) { Invalid = Get.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } if (Set != null) { Invalid = Set.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } Invalid = FieldType.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); }
internal override void AccumUsedTypeAndMemberDefs(ValidityContext vctxt, AssemblyDef assemblyDef, TypeDef typeDef) { base.AccumUsedTypeAndMemberDefs(vctxt, assemblyDef, typeDef); var ctxt = MessageContextBuilders.Member(vctxt.Global, assemblyDef, typeDef, this); if (Add != null) { Invalid = Add.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } if (Remove != null) { Invalid = Remove.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); if (Invalid != null) { return; } } Invalid = HandlerType.AccumUsedTypeDefs(vctxt, ctxt, usedTypes); }
public void Check() { if (tracer != null) { tracer.AppendLine("Check {"); tracer.Indent(); } try { Stats("initial"); // Phase 1: // - Discover used root types and methods // - Fixup assembly entry points // - Lazily check names are valid, build the 'uses' and 'used-by' graph, and fixup some // value-vs-ref type issues deferred by the loader. // - Propogate initial usedness (will be refined later). var rootMembers = new Seq <QualifiedMemberName>(); var rootTypes = new Seq <QualifiedTypeName>(); foreach (var assemblyDef in Global.Assemblies) { var entryPoint = default(MethodRef); foreach (var typeDef in assemblyDef.Types) { if (TypeAlwaysUsed(assemblyDef, typeDef)) { rootTypes.Add(typeDef.QualifiedTypeName(Global, assemblyDef)); typeDef.MarkAsUsed(this, assemblyDef); } foreach (var memberDef in typeDef.Members) { var alwaysUsed = default(bool); switch (memberDef.Flavor) { case MemberDefFlavor.Field: { var fieldDef = (FieldDef)memberDef; alwaysUsed = FieldAlwaysUsed(assemblyDef, typeDef, fieldDef); break; } case MemberDefFlavor.Method: { var methodDef = (MethodDef)memberDef; if (IsAlternateEntryPoint(assemblyDef, typeDef, methodDef)) { var methodRef = methodDef.PrimMethodReference (Global, assemblyDef, typeDef, null, null); if (entryPoint != null) { Log(new DuplicateEntryPointMessage(entryPoint, methodRef)); throw new ExitException(); } entryPoint = methodRef; // Will mark below } else { alwaysUsed = MethodAlwaysUsed(assemblyDef, typeDef, methodDef); } break; } case MemberDefFlavor.Event: { var eventDef = (EventDef)memberDef; alwaysUsed = EventAlwaysUsed(assemblyDef, typeDef, eventDef); break; } case MemberDefFlavor.Property: { var propDef = (PropertyDef)memberDef; alwaysUsed = PropertyAlwaysUsed(assemblyDef, typeDef, propDef); break; } default: throw new ArgumentOutOfRangeException(); } if (alwaysUsed) { rootMembers.Add(memberDef.QualifiedMemberName(Global, assemblyDef, typeDef)); memberDef.MarkAsUsed(this, assemblyDef, typeDef); } } } if (entryPoint == null) { entryPoint = assemblyDef.EntryPoint; } else { assemblyDef.EntryPoint = entryPoint; } if (entryPoint != null) { // Entry points are implicity used var entryAssemblyDef = default(AssemblyDef); var entryTypeDef = default(TypeDef); var entryMemberDef = default(MemberDef); if (entryPoint.PrimTryResolve (Global, out entryAssemblyDef, out entryTypeDef, out entryMemberDef)) { rootMembers.Add (entryMemberDef.QualifiedMemberName(Global, entryAssemblyDef, entryTypeDef)); entryMemberDef.MarkAsUsed(this, entryAssemblyDef, entryTypeDef); } } } var anyMarkedAsUsed = default(bool); var iter = 0; do { anyMarkedAsUsed = false; // Phase 2: Construct topological sort of used types and members // (later only depends on earlier unless in a scc) var visitedTypeDefs = new Set <QualifiedTypeName>(); var sortedTypeDefs = new Seq <QualifiedTypeName>(); var visitedMemberDefs = new Set <QualifiedMemberName>(); var sortedMemberDefs = new Seq <QualifiedMemberName>(); foreach (var assemblyDef in Global.Assemblies) { foreach (var typeDef in assemblyDef.Types) { typeDef.TopologicalAllDeps(Global, assemblyDef, visitedTypeDefs, sortedTypeDefs); foreach (var memberDef in typeDef.Members) { memberDef.TopologicalAllDeps (Global, assemblyDef, typeDef, visitedMemberDefs, sortedMemberDefs); } } } // Phase 3: Construct strongly connected components of types and members visitedTypeDefs = new Set <QualifiedTypeName>(); var typeScc = new Seq <QualifiedTypeName>(); var typeSccs = new Seq <Seq <QualifiedTypeName> >(); for (var i = sortedTypeDefs.Count - 1; i >= 0; i--) { var r = sortedTypeDefs[i]; var assemblyDef = default(AssemblyDef); var typeDef = default(TypeDef); if (r.PrimTryResolve(Global, out assemblyDef, out typeDef)) { typeDef.UsedByTypesClosure(Global, assemblyDef, visitedTypeDefs, typeScc); if (typeScc.Count > 0) { typeSccs.Add(typeScc); typeScc = new Seq <QualifiedTypeName>(); } } } visitedMemberDefs = new Set <QualifiedMemberName>(); var memberScc = new Seq <QualifiedMemberName>(); var memberSccs = new Seq <Seq <QualifiedMemberName> >(); for (var i = sortedMemberDefs.Count - 1; i >= 0; i--) { var r = sortedMemberDefs[i]; var assemblyDef = default(AssemblyDef); var typeDef = default(TypeDef); var memberDef = default(MemberDef); if (r.PrimTryResolve(Global, out assemblyDef, out typeDef, out memberDef)) { memberDef.UsedByMembersClosure(Global, assemblyDef, typeDef, visitedMemberDefs, memberScc); if (memberScc.Count > 0) { memberSccs.Add(memberScc); memberScc = new Seq <QualifiedMemberName>(); } } } // Phase 4: Propogate failures known so far // (next step is expensive so good to avoid invalid definitions asap) PropogateInvalidity(typeSccs, memberSccs); Stats("iter " + iter + ", after first propogation"); // Phase 5: // - Check validity of types and members // - Fill-in the slot implementations for types // - Construct the slot-to-implementations graph. var rootEnv = Global.Environment(); foreach (var assemblyDef in Global.Assemblies) { var assmEnv = rootEnv.AddAssembly(assemblyDef); foreach (var typeDef in assemblyDef.Types.Where(t => t.Invalid == null && t.IsUsed)) { var typeEnv = assmEnv.AddType(typeDef).AddSelfTypeBoundArguments(); typeDef.CheckValid(this, typeEnv); foreach (var memberDef in typeDef.Members.Where(m => m.Invalid == null && m.IsUsed)) { memberDef.CheckValid(this, typeEnv); } } } // Phase 6: Propogate any new failures discovered by above PropogateInvalidity(typeSccs, memberSccs); Stats("iter " + iter + ", after second propogation"); // Phase 7: Look for additional definitions to mark as used // (couldn't do so earlier since types weren't yet initialized) foreach (var assemblyDef in Global.Assemblies) { foreach (var typeDef in assemblyDef.Types.Where(t => t.IsUsed && t.Invalid == null)) { if (PropogateExtraUsedFromType(assemblyDef, typeDef)) { anyMarkedAsUsed = true; } foreach (var memberDef in typeDef.Members.Where(m => m.IsUsed && m.Invalid == null)) { if (PropogateExtraUsedFromMember(assemblyDef, typeDef, memberDef)) { anyMarkedAsUsed = true; } } } } // Phase 8: Complete according to: // - used virtual/iface method and used implementing type => used override/impl methods of that type // - invalid overrifde/impl method => invalid virtual/iface method // - virtual/iface method must have a def and used implementing type => used override/impl methods of that type must have a def foreach (var assemblyDef in Global.Assemblies) { foreach (var typeDef in assemblyDef.Types) { foreach (var methodDef in typeDef.Members.OfType <MethodDef>().Where(d => d.IsUsed && d.Implementors != null)) { var slot = methodDef.QualifiedMemberName(Global, assemblyDef, typeDef); var forceDefinitions = IsMustHaveADefinition(slot); foreach (var impl in methodDef.Implementors) { var implAssemblyDef = default(AssemblyDef); var implTypeDef = default(TypeDef); var implMemberDef = default(MemberDef); if (impl.PrimTryResolve (Global, out implAssemblyDef, out implTypeDef, out implMemberDef)) { if (implTypeDef.IsUsed) { if (forceDefinitions) { mustHaveADefinitionCache.Add(impl); } if (implMemberDef.MarkAsUsed(this, assemblyDef, typeDef)) { anyMarkedAsUsed = true; } if (implMemberDef.Invalid != null && methodDef.Invalid == null) { methodDef.Invalid = new CST.InvalidInfo (MessageContextBuilders.Member (Global, implAssemblyDef, implTypeDef, implMemberDef), implMemberDef.Invalid); } } } } } } } // Phase 9: Propogate any new failures discovered by above PropogateInvalidity(typeSccs, memberSccs); Stats("iter " + iter + ", after third propogation"); iter++; }while (anyMarkedAsUsed); // Phase 10: Check roots are valid foreach (var typeName in rootTypes) { var assemblyDef = default(AssemblyDef); var typeDef = default(TypeDef); if (typeName.PrimTryResolve(Global, out assemblyDef, out typeDef)) { if (typeDef.Invalid != null) { Log (new UnimplementableUsedTypeMessage (MessageContextBuilders.Type(Global, assemblyDef, typeDef), typeDef.Invalid)); throw new ExitException(); } } } foreach (var methodName in rootMembers) { var assemblyDef = default(AssemblyDef); var typeDef = default(TypeDef); var memberDef = default(MemberDef); if (methodName.PrimTryResolve(Global, out assemblyDef, out typeDef, out memberDef)) { if (memberDef.Invalid != null) { Log (new UnimplementableRootMethodMessage (MessageContextBuilders.Member(Global, assemblyDef, typeDef, memberDef), memberDef.Invalid)); throw new ExitException(); } } } // Phase 11: Construct topological sort of type's according to their .cctor 'used' graph typeInitializationOrder = new Seq <QualifiedTypeName>(); var visitedTypeDefs2 = new Set <QualifiedTypeName>(); foreach (var assemblyDef in Global.Assemblies) { foreach (var typeDef in assemblyDef.Types) { typeDef.TopologicalTypeInit(Global, assemblyDef, visitedTypeDefs2, typeInitializationOrder); } } } finally { if (tracer != null) { tracer.Outdent(); tracer.AppendLine("}"); } } }
private void PropogateInvalidity(Seq <Seq <QualifiedTypeName> > typeSccs, Seq <Seq <QualifiedMemberName> > memberSccs) { for (var i = typeSccs.Count - 1; i >= 0; i--) { var typeScc = typeSccs[i]; if (typeScc.Count == 1) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); if (typeScc[0].PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef)) { sccTypeDef.PropogateInvalidity(Global, sccAssemblyDef); } } else { // Check if entire scc is valid var invalid = default(InvalidInfo); foreach (var r in typeScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef)) { if (sccTypeDef.Invalid != null) { invalid = new InvalidInfo (MessageContextBuilders.Type(Global, sccAssemblyDef, sccTypeDef), sccTypeDef.Invalid); break; } } } if (invalid != null) { // Fail entire scc foreach (var r in typeScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef)) { if (sccTypeDef.Invalid == null) { sccTypeDef.Invalid = invalid; } } } // Propogate failure foreach (var r in typeScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef)) { sccTypeDef.PropogateInvalidity(Global, sccAssemblyDef); } } } } } for (var i = memberSccs.Count - 1; i >= 0; i--) { var memberScc = memberSccs[i]; if (memberScc.Count == 1) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); var sccMemberDef = default(MemberDef); if (memberScc[0].PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef, out sccMemberDef)) { sccMemberDef.PropogateInvalidity(Global, sccAssemblyDef, sccTypeDef); var sccMethodDef = sccMemberDef as CST.MethodDef; if (sccMethodDef != null) { // Check if method is recursive if (sccMethodDef.UsedMembers.Contains(memberScc[0])) { sccMethodDef.IsRecursive = true; } } } } else if (memberScc.Count > 1) { // Check if entire scc is valid, and mark methods as recursive var invalid = default(InvalidInfo); foreach (var r in memberScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); var sccMemberDef = default(MemberDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef, out sccMemberDef)) { if (sccMemberDef.Invalid != null && invalid == null) { invalid = new InvalidInfo (MessageContextBuilders.Member(Global, sccAssemblyDef, sccTypeDef, sccMemberDef), sccMemberDef.Invalid); } var sccMethodDef = sccMemberDef as CST.MethodDef; if (sccMethodDef != null) { sccMethodDef.IsRecursive = true; } } } if (invalid != null) { // Fail entire scc foreach (var r in memberScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); var sccMemberDef = default(MemberDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef, out sccMemberDef)) { if (sccMemberDef.Invalid == null) { sccMemberDef.Invalid = invalid; } } } // Propogate failure foreach (var r in memberScc) { var sccAssemblyDef = default(AssemblyDef); var sccTypeDef = default(TypeDef); var sccMemberDef = default(MemberDef); if (r.PrimTryResolve(Global, out sccAssemblyDef, out sccTypeDef, out sccMemberDef)) { sccMemberDef.PropogateInvalidity(Global, sccAssemblyDef, sccTypeDef); } } } } } }
internal override void CheckValid(ValidityContext vctxt, TypeEnvironment typeEnv) { if (Invalid != null || typeEnv.Type.Invalid != null) { return; } var methEnv = typeEnv.AddMethod(this).AddSelfMethodBoundArguments(); for (var i = 0; i < TypeParameters.Count; i++) { TypeParameters[i].CheckValid(vctxt, methEnv); if (TypeParameters[i].Invalid != null) { Invalid = new InvalidInfo (MessageContextBuilders.TypeArg(ParameterFlavor.Method, i), TypeParameters[i].Invalid); return; } } var ctxt = MessageContextBuilders.Member(vctxt.Global, typeEnv.Assembly, typeEnv.Type, this); foreach (var p in ValueParameters) { Invalid = p.Type.CheckValid(vctxt, ctxt, methEnv); if (Invalid != null) { return; } } if (Result != null) { Invalid = Result.Type.CheckValid(vctxt, ctxt, methEnv); if (Invalid != null) { return; } } if (vctxt.IgnoreMethodDefBody(typeEnv.Assembly, typeEnv.Type, this)) { return; } foreach (var l in Locals) { Invalid = l.Type.CheckValid(vctxt, ctxt, methEnv); if (Invalid != null) { return; } } var instructions = Instructions(vctxt.Global); if (instructions != null) { foreach (var i in instructions.Body) { Invalid = i.CheckValid(vctxt, ctxt, methEnv); if (Invalid != null) { return; } Invalid = vctxt.ImplementableInstruction(ctxt, methEnv.Assembly, methEnv.Type, this, i); if (Invalid != null) { return; } } } vctxt.ImplementableMemberDef(typeEnv.Assembly, typeEnv.Type, this); }