// WriteType inference #region overloadResolution() /// <summary> /// A public method for being used as a global overload resolution process /// </summary> /// <param name="arguments">The ordered types of actual parameters</param> /// <param name="fileName"></param> /// <param name="line"></param> /// <param name="column"></param> /// <returns>The actual method called (a union type if more than one is suitable)</returns> public TypeExpression overloadResolution(TypeExpression[] arguments, Location location) { int aux; int min = -1, index = -1, minNumFreeVariables = Int32.MaxValue; // * We create a dictionary of <index,promotionValue> to remember the promotion values (they could have // repeated values because of type variables) Dictionary <int, int> promotionValues = new Dictionary <int, int>(); if (this.typeSet.Count == 0) { System.Diagnostics.Debug.Assert(false, "There should be no empty intersection types."); return(null); } for (int i = 0; i < this.typeSet.Count; i++) { MethodType mt = TypeExpression.As <MethodType>(this.typeSet[i]); if (mt == null) { ErrorManager.Instance.NotifyError(new OperationNotAllowedError("()", mt.FullName, location)); } aux = mt.Promotion(arguments, location); if (aux != -1) { if ((min >= aux) || (min == -1)) { min = aux; index = i; promotionValues[index] = min; } } } // * No method is suitable if (index == -1) { ErrorManager.Instance.NotifyError(new UnknownMemberError(location)); return(null); } index = -1; // * Gets the min number of free variables foreach (KeyValuePair <int, int> pair in promotionValues) { if (pair.Value == min) { aux = ((MethodType)this.typeSet[pair.Key]).GetNumberFreeVariables(); if (aux < minNumFreeVariables) { minNumFreeVariables = aux; } } } // * Assigns a union of all the best methods TypeExpression bestMethods = null; foreach (KeyValuePair <int, int> pair in promotionValues) { if (pair.Value == min && ((MethodType)this.typeSet[pair.Key]).GetNumberFreeVariables() == minNumFreeVariables) { bestMethods = UnionType.collect(bestMethods, this.typeSet[pair.Key]); } } // * We've got'em return(bestMethods); }
// 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 (!this.HasTypeVariables()) { return(this); } IntersectionType newIntersectionType = (IntersectionType)this.MemberwiseClone(); newIntersectionType.typeSet = new List <TypeExpression>(); // * Clones all the types in the union foreach (TypeExpression type in this.typeSet) { newIntersectionType.typeSet.Add(type.Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed)); } return(newIntersectionType); }
// 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); }
// 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 virtual TypeExpression Clone(IDictionary <int, TypeVariable> clonedTypeVariables, IList <EquivalenceClass> equivalenceClasses, MethodType methodAnalyzed) { if (this.HasTypeVariables()) { throw new InvalidOperationException("The type should implement a Clone method."); } // * Default implementation (types with no type variables) return(this); }
// 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); }
// 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) { // * Methods are not cloned return(this); }
// 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 (!this.HasTypeVariables()) { return(this); } ArrayType newType = (ArrayType)this.MemberwiseClone(); newType.arrayType = newType.arrayType.Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed); newType.ValidTypeExpression = false; return(newType); }
internal TypeExpression Clone(IDictionary <int, TypeVariable> clonedTypeVariables, IList <EquivalenceClass> equivalenceClasses, MethodType methodAnalyzed, IDictionary <String, TypeExpression> evaluated) { if (!this.HasTypeVariables()) { return(this); } FieldType newFieldType = (FieldType)this.MemberwiseClone(); if (newFieldType.fieldType is ClassType) { newFieldType.fieldType = ((ClassType)newFieldType.fieldType).Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed, evaluated); } else if (newFieldType.fieldType != null) { newFieldType.fieldType = newFieldType.fieldType.Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed); } newFieldType.ValidTypeExpression = false; return(newFieldType); }
// SSA #region CloneTypeVariables() /// <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 void CloneTypeVariables(IDictionary <int, TypeVariable> clonedTypeVariables, IList <EquivalenceClass> equivalenceClasses, MethodType methodAnalyzed) { // * Checks if the equivalence class has been already cloned if (equivalenceClasses.Contains(this)) { return; } // * Adds class equivalence equivalenceClasses.Add(this); // * Clones, but not updates, the substitution if (this.substitution != null) { this.substitution.Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed); } // * Clones all the type variables in the equivalence class foreach (KeyValuePair <int, TypeVariable> pair in this.typeVariables) { pair.Value.Clone(clonedTypeVariables, equivalenceClasses, methodAnalyzed); } }