// Loop Detection #region Remove() /// <summary> /// When loops are detected, it is necesary to suppress a new extra variable returned in /// the return type of recursive functions /// </summary> /// <param name="toRemove">The type variable to remove</param> /// <returns>If it has been actually removed</returns> public override bool Remove(TypeVariable toRemove) { int i; for (i = 0; i < this.typeSet.Count; i++) { TypeVariable typeVariable = this.typeSet[i] as TypeVariable; if (typeVariable != null && typeVariable.Variable == toRemove.Variable) { this.typeSet.RemoveAt(i); this.ValidTypeExpression = false; break; } if (this.typeSet[i].Remove(toRemove)) { this.typeSet[i].ValidTypeExpression = false; break; } } return(i < this.typeSet.Count); }
// Helper Methods #region IsConcreteType() /// <summary> /// Tells if the parameter is a concrete class type /// </summary> /// <param name="actualImplicitObject">The object's type</param> /// <returns>The appropriate class type if the parameter is a concret object</returns> public static ClassType IsConcreteType(TypeExpression actualImplicitObject) { TypeVariable typeVariable = actualImplicitObject as TypeVariable; if (typeVariable != null) { actualImplicitObject = typeVariable.Substitution; } ClassType classType = actualImplicitObject as ClassType; if (classType != null && classType.ConcreteType) { return(classType); } UnionType unionType = actualImplicitObject as UnionType; if (unionType != null && unionType.Count > 0) { return(IsConcreteType(unionType.TypeSet[0])); } return(null); }
// SSA #region Clone() /// <summary> /// Clones a type to be used in SSA. It must taken into account that: /// - In case it has no type variables, no clone is performed /// - WriteType variables, equivalence classes and substitutions are cloned /// </summary> /// <param name="clonedTypeVariables">WriteType variables that have been cloned.</param> /// <param name="equivalenceClasses">Equivalence classes of the type cloned variables. These /// equivalence classes need to be updated with the new cloned type variables.</param> /// <param name="methodAnalyzed">The method that is being analyzed when the operation is performed.</param> /// <returns>The cloned type</returns> internal override TypeExpression Clone(IDictionary <int, TypeVariable> clonedTypeVariables, IList <EquivalenceClass> equivalenceClasses, MethodType methodAnalyzed) { if (clonedTypeVariables.ContainsKey(this.variable)) { // * Already cloned return(clonedTypeVariables[this.variable]); } if (this.Substitution != null) { // * Lets clone it TypeVariable newTypeVariable = (TypeVariable)this.MemberwiseClone(); newTypeVariable.variable = TypeVariable.NewTypeVariable.Variable; // * We add it to the list clonedTypeVariables[this.variable] = newTypeVariable; // * We also clone all the type variables of its class equivalence if (newTypeVariable.equivalenceClass != null) { newTypeVariable.equivalenceClass.CloneTypeVariables(clonedTypeVariables, equivalenceClasses, methodAnalyzed); } newTypeVariable.BuildFullName(); newTypeVariable.BuildTypeExpressionString(2); return(newTypeVariable); } if (methodAnalyzed != null) { // * A clone constraint is added to the method analyzed CloneConstraint constraint = new CloneConstraint(this); methodAnalyzed.AddConstraint(constraint); // * We add it to the list clonedTypeVariables[this.variable] = constraint.ReturnType; // * We also clone all the type variables of its class equivalence if (this.equivalenceClass != null) { this.equivalenceClass.CloneTypeVariables(clonedTypeVariables, equivalenceClasses, methodAnalyzed); } return(constraint.ReturnType); } return(null); }
/// <summary> /// Replaces type variables substituting the old type variables for the new ones. /// </summary> /// <param name="typeVariableMappings">Each new type varaiable represent a copy of another existing one. /// This parameter is a mapping between them, wher tmpName=old and value=new.</param> public override void ReplaceTypeVariables(IDictionary <TypeVariable, TypeVariable> typeVariableMappings) { if (!this.HasTypeVariables()) { return; } for (int i = 0; i < this.typeSet.Count; i++) { TypeVariable typeVariable = this.typeSet[i] as TypeVariable; if (typeVariable == null) { if (this.typeSet[i].HasTypeVariables()) { this.typeSet[i].ReplaceTypeVariables(typeVariableMappings); } } else if (typeVariableMappings.ContainsKey(typeVariable)) { this.typeSet[i] = typeVariableMappings[typeVariable]; } this.ValidTypeExpression = false; } }
/// <summary> /// Replaces the equivalence class substituting the old type variables for the new ones. /// The substitution is not altered. /// Since equivalence classes and type variables have a bidirectional association, /// the new equivalence classes will make type variables update their new equivalence classes. /// </summary> /// <param name="typeVariableMappings">Each new type varaiable represent a copy of another existing one. /// This parameter is a mapping between them, wher tmpName=old and value=new.</param> public void UpdateEquivalenceClass(IDictionary <TypeVariable, TypeVariable> typeVariableMappings) { // * Creates a new equivalence class EquivalenceClass newEquivalenceClass = new EquivalenceClass(); // * We take the existing substitution... newEquivalenceClass.substitution = this.substitution; // ... changing old type variables for new ones if (newEquivalenceClass.substitution != null) { newEquivalenceClass.substitution.ReplaceTypeVariables(typeVariableMappings); } // * We update all the appropiate type variables newEquivalenceClass.typeVariables = new Dictionary <int, TypeVariable>(); foreach (KeyValuePair <int, TypeVariable> oldPair in this.typeVariables) { // * Is there a new type variable for the existing one? if (typeVariableMappings.ContainsKey(oldPair.Value)) { // * We create a new entry with the new one... TypeVariable newTypeVariable = typeVariableMappings[oldPair.Value]; newEquivalenceClass.typeVariables[newTypeVariable.Variable] = newTypeVariable; // * ... and updates the class equivalence of the new type variable newTypeVariable.EquivalenceClass = newEquivalenceClass; newTypeVariable.ValidTypeExpression = false; } else // * Otherwise, the old one is kept { newEquivalenceClass.typeVariables[oldPair.Key] = oldPair.Value; } } // * Finally, we update all the equivalence classes of the substitution if its exists if (newEquivalenceClass.substitution != null) { newEquivalenceClass.substitution.UpdateEquivalenceClass(typeVariableMappings, new List <TypeExpression>()); } }
/// <summary> /// To add a new type to the class equivalence. /// </summary> /// <param name="te">The type to be added</param> /// <param name="unification">Indicates if the kind of unification (equivalent, incremental or override).</param> /// <param name="previouslyUnified">To detect infinite loops. The previously unified pairs of type expressions.</param> /// <returns>If the substitution has been correctly applied</returns> public bool add(TypeExpression te, SortOfUnification unification, IList <Pair <TypeExpression, TypeExpression> > previouslyUnified) { TypeVariable tv = te as TypeVariable; if (tv != null) // * Another type variable // * Tries to add its substitution { if (tv.Substitution != null) // * If it has a substitution { if (!this.add(tv.EquivalenceClass.Substitution, unification, previouslyUnified)) // * We try to add it to ourselves { return(false); // * Both susbstitutions are not the same } } // * If no error, we add it to the equivalence class this.typeVariables[tv.Variable] = tv; if (tv.EquivalenceClass != null) // * The parameter already has a equivalence class { foreach (KeyValuePair <int, TypeVariable> pair in tv.EquivalenceClass.TypeVariables) { if (!this.typeVariables.ContainsKey(pair.Key)) { // * We recursively add all the element of the equivalence class this.typeVariables[pair.Key] = pair.Value; this.add(pair.Value, unification, previouslyUnified); } } } // * Finally, we update the equivalence class of tv tv.EquivalenceClass = this; return(true); } // * te is not a type variable if (this.substitution != null) { // * A substitution already exists if (unification == SortOfUnification.Equivalent) { // * They must be equivalent if (!(bool)this.substitution.AcceptOperation(new EquivalentOperation(te), null)) { return(false); } if (te.HasTypeVariables()) { // var1=Array(int) must be unified to Array(var1) return(te.Unify(this.substitution, unification, previouslyUnified)); } return(true); } if (unification == SortOfUnification.Incremental) { // * The incremental behaviour implies a union of all the types this.substitution = UnionType.collect(this.substitution, te); return(true); } // * Override unification (the susbstitution is overridden) this.substitution = te; return(true); } // * We set the type as a susbstitution substitution = te; return(true); }
// Loop Detection /// <summary> /// When loops are detected, it is necesary to suppress a new extra variable returned in /// the return type of recursive functions /// </summary> /// <param name="toRemove">The type variable to remove</param> /// <returns>If it has been actually removed</returns> public bool Remove(TypeVariable toRemove) { return(this.typeVariables.Remove(toRemove.Variable)); }
// WriteType Promotion #region PromotionLevel() /// <summary> /// Returns a value thdat indicates a promotion level. /// </summary> /// <param name="type">WriteType to promotion.</param> /// <returns>Returns a promotion value.</returns> //public override int PromotionLevel(TypeExpression type) { // int aux, less = -1; // // * The same type // if (this == type) // return 0; // // * Equivalent types // if ((bool)this.AcceptOperation(new EquivalentOperation(type))) // return 0; // // * Field type and bounded type variable // FieldType fieldType = TypeExpression.As<FieldType>(type); // if (fieldType != null) // return this.PromotionLevel(fieldType.FieldTypeExpression); // // * WriteType variable // TypeVariable typeVariable = type as TypeVariable; // if (typeVariable != null) { // if (typeVariable.Substitution != null) // // * If the variable is bounded, the promotion is the one of its substitution // return this.PromotionLevel(typeVariable.EquivalenceClass.Substitution); // // * A free variable is complete promotion // return 0; // } // // * Inheritance // if (this.BaseClass == null) // // * Object only promotes to object // return -1; // if ((bool)this.baseClass.AcceptOperation(new EquivalentOperation(type))) // return 1; // else { // aux = this.baseClass.PromotionLevel(type); // if (aux != -1) // return aux + 1; // } // // * Interfaces // if (this.interfaceList.Count != 0) { // for (int i = 0; i < this.interfaceList.Count; i++) { // if ((bool)this.interfaceList[i].AcceptOperation( new EquivalentOperation(type))) { // if ((less > 1) || (less == -1)) // less = 1; // } // else { // aux = this.interfaceList[i].PromotionLevel(type); // if (aux != -1) { // if ((less > (aux + 1)) || (less == -1)) // less = aux + 1; // } // } // } // } // if (less != -1) // return less; // // * Union type // UnionType unionType = TypeExpression.As<UnionType>(type); // if (unionType != null) // return unionType.SuperType(this); // // * No promotion // return -1; //} #endregion // WriteType Unification #region Unify /// <summary> /// This method unifies two type expressions (this and te) /// </summary> /// <param name="te">The expression to be unfied with this</param> /// <param name="unification">Indicates if the kind of unification (equivalent, incremental or override).</param> /// <param name="previouslyUnified">To detect infinite loops. The previously unified pairs of type expressions.</param> /// <returns>If the unification was successful</returns> public override bool Unify(TypeExpression te, SortOfUnification unification, IList <Pair <TypeExpression, TypeExpression> > previouslyUnified) { // * Infinite recursion detection Pair <TypeExpression, TypeExpression> pair = new Pair <TypeExpression, TypeExpression>(this, te); if (previouslyUnified.Contains(pair)) { return(true); } previouslyUnified.Add(pair); ClassType ct = te as ClassType; bool success = true; // * Class WriteType if (ct != null) { // * Inheritance is taken into account if ((int)ct.AcceptOperation(new PromotionLevelOperation(this), null) == -1) { return(false); } // * Walk upward in the tree till find the correct class while (!(bool)ct.AcceptOperation(new EquivalentOperation(this), null)) { ct = ct.baseClass; } // * Now we unify the fields foreach (string key in this.Fields.Keys) { FieldType thisField = (FieldType)this.Fields[key].Type, teField = (FieldType)ct.Fields[key].Type; if (thisField.FieldTypeExpression is ClassTypeProxy || teField.FieldTypeExpression is ClassTypeProxy) { success = thisField.FieldTypeExpression.FullName.Equals(teField.FieldTypeExpression.FullName); } else if (!(thisField.Unify(teField, unification, previouslyUnified))) { success = false; } if (!success) { break; } } if (success && this.baseClass != null) { // * The same with the base class this.baseClass.Unify(ct.baseClass, unification, previouslyUnified); } // * If one of the classes is a concrete type, so it is the other if (success) { this.ConcreteType = ct.ConcreteType = this.ConcreteType || ct.ConcreteType; } } // * WriteType variable else if (te is TypeVariable) { TypeVariable typeVariable = (TypeVariable)te; if (unification != SortOfUnification.Incremental) { // * Incremental is commutative success = typeVariable.Unify(this, unification, previouslyUnified); } // * Incremental unification (not commutative) else if (typeVariable.Substitution != null) { // * Class(var) should unify to Var=Class(int) success = this.Unify(typeVariable.Substitution, unification, previouslyUnified); } else { success = false; } } // * Union WriteType else if (te is UnionType) { success = te.Unify(this, unification, previouslyUnified); } // * Class WriteType Proxy else if (te is ClassTypeProxy) { success = this.Unify(((ClassTypeProxy)te).RealType, unification, previouslyUnified); } else if (te is FieldType) { success = this.Unify(((FieldType)te).FieldTypeExpression, unification, previouslyUnified); } else { success = false; } // * Clears the type expression cache this.ValidTypeExpression = false; te.ValidTypeExpression = false; return(success); }
// Loop Detection #region Remove() /// <summary> /// When loops are detected, it is necesary to suppress a new extra variable returned in /// the return type of recursive functions /// </summary> /// <param name="toRemove">The type variable to remove</param> /// <returns>If it has been actually removed</returns> public virtual bool Remove(TypeVariable toRemove) { return(false); }
// Loop Detection // Helper Methods #region methodCall() /// <summary> /// This method does the type inference in a method call including unification. /// It requires that a) the method to be invoked has been previously analyzed with this visitor /// b) The formalMethod parameter is the result of the overload resolution /// </summary> /// <param name="actualImplicitObject">The actual implicit object</param> /// <param name="formalMethod">The formal method to be called</param> /// <param name="args">The ordered types of the actual parameters</param> /// <param name="methodAnalyzed">The method that is being analyzed when the operation is performed.</param> /// <param name="activeSortOfUnification">The active sort of unification used (Equivalent is the default /// one and Incremental is used in the SSA bodies of the while, for and do statements)</param> /// <param name="fileName">File name.</param> /// <param name="line">Line number.</param> /// <param name="column">Column number.</param> /// <returns>The type expression of the returned value</returns> public static TypeExpression methodCall(TypeExpression actualImplicitObject, MethodType formalMethod, TypeExpression[] args, MethodType methodAnalyzed, SortOfUnification activeSortOfUnification, Location location) { UserType userType = formalMethod.MemberInfo.Class; MethodType actualMethod = null; // * We must create a new type with type variables for the object's attributes (the formal implicit object) IDictionary <TypeVariable, TypeVariable> typeVariableMappings = new Dictionary <TypeVariable, TypeVariable>(); // * If the method is an instance one and the actual object is not this, we create a new implicit object to unify if (!formalMethod.MemberInfo.hasModifier(Modifier.Static) && actualImplicitObject != null && actualImplicitObject != methodAnalyzed.memberInfo.Class) { // * Unifies the implicit objects (actual and formal) UserType formalImplicitObject = (UserType)userType.CloneType(typeVariableMappings); if (!actualImplicitObject.Unify(formalImplicitObject, SortOfUnification.Equivalent, new List <Pair <TypeExpression, TypeExpression> >())) { // * If the formal implicit object already has substitution (fields declararion with assignments), we override it with a union type formalImplicitObject.Unify(actualImplicitObject, SortOfUnification.Override, new List <Pair <TypeExpression, TypeExpression> >()); } actualImplicitObject.ValidTypeExpression = false; } // * If "this" is the actual implicit object, the return type is the original return type of the method TypeExpression originalReturnType = formalMethod.Return; if (formalMethod.HasTypeVariables() || formalMethod.Constraints.Count > 0) { // * We must also generate a method with fresh variables (formal method) // when it has parameters with type variables or constraints formalMethod = formalMethod.CloneMethodType(typeVariableMappings); } // * If the method has type variables... if (formalMethod.HasTypeVariables()) { // * We create the actual method: // 1.- The actual return type TypeVariable actualReturnType = TypeVariable.NewTypeVariable; // 2.- The actual method actualMethod = new MethodType(actualReturnType); // 3.- The actual parameters foreach (TypeExpression arg in args) { actualMethod.AddParameter(arg); } // * Unifies both methods if (!actualMethod.Unify(formalMethod, SortOfUnification.Equivalent, new List <Pair <TypeExpression, TypeExpression> >())) { ErrorManager.Instance.NotifyError(new UnificationError(actualMethod.FullName, location)); return(null); } } // * Otherwise, arguments promotion must be checked else { if (args.Length != formalMethod.ParameterListCount) { ErrorManager.Instance.NotifyError(new ArgumentNumberError(formalMethod.FullName, args.Length, location)); return(null); } for (int i = 0; i < args.Length; i++) { if (args[i].AcceptOperation(PromotionOperation.Create(formalMethod.paramList[i], methodAnalyzed, location), null) == null) { return(null); } } } // * Method constraints satisfaction if (formalMethod.Constraints.Count > 0) { formalMethod.Constraints.Check(methodAnalyzed, actualImplicitObject, true, activeSortOfUnification, location); } // * The returned type is the the actual method if there has been a unification and // in case the method is a instance method, a concrete object has been used (not this) or // a different implicit object (the this reference is changed in the SSA algorithm) if (actualMethod != null && (formalMethod.MemberInfo.hasModifier(Modifier.Static) || ClassType.IsConcreteType(actualImplicitObject) != null || actualImplicitObject != formalMethod.MemberInfo.Class)) { TypeVariable returnType = (TypeVariable)actualMethod.Return; if (returnType.Substitution != null) { return(returnType.EquivalenceClass.Substitution); } return(returnType); } // * The original returned type if there has been no unification or the implicit object is "this" return(originalReturnType); }