/** * 15.12.2.7: Inferring Type Arguments Based on Actual Arguments * * @author Martin Bravenboer */ module dryad/type-check/invoke/InferringTypeArguments imports dryad/jls/types/Main dryad/jls/types/Lub dryad/type-check/invoke/Constraints dryad/type-check/invoke/ConstraintReduction strategies /** * Given a list of initial constraints, infers the type arguments for * all formal type parameters of the method. * * @type Method Object -> Hashtable(TypeVar, List(Type)) */ infer-type-arguments(|initial-constraints) = ?method ; where( get-formal-type-parameters ; map(type-param-to-type-variable(|method)) ; ?tvs ) ; <infer-type-arguments-from-constraints(|tvs)> initial-constraints /** * @param List(TypeVar) * @type List(Constraint) -> Hashtable(TypeVar, List(Type)) */ infer-type-arguments-from-constraints(|tvs) = map(reduce-constraint(|tvs)) ; concat ; resolve-constraints(|tvs) type-param-to-type-variable(|method) : TypeParam(Id(x), _) -> TypeVar(<get-name> method, Id(x)) /** * Result list can contain duplicates, even with different values for * illegal invocations. These should usually be reported as errors by the * invoker of this strategy. * * @param List(TypeVar) * @type List(Constraint) -> Hashtable(TypeVar, List(Type)) */ resolve-constraints(|typevars) = where( new-hashtable => results ; <map({t: ?t; <hashtable-put(|t, [])> results})> typevars ) ; resolve-implied-equality-constraints(|results) ; resolve-supertype-constaints(|typevars, results) ; !results /** * 15.12.2.7: Page 463. */ strategies /** * @param Hashtable(TypeVar, List(Type)) * @type List(Constraint) -> List(Constraint) */ resolve-implied-equality-constraints(|results) = partition(?Constraint(Equal(), _, _)) => (ceq, csuper) ; let threader(|c) = {cs: ?cs ; <resolve-implied-equality-constraint(|cs, results)> c } in <foldl(threader | ceq)> csuper end /** * From Tj = U, where U is not a type variable. * * @todo Should the lhs be rewritten? * @todo Should equality constrains be rewritten? */ resolve-implied-equality-constraint(|constraints, results) = ?Constraint(Equal(), t, u) ; where(not(<hashtable-get(|u)> results)) ; <map(Constraint(id, id, topdown( (t -> u) )))> constraints ; where(<hashtable-push-existing(|t, u)> results) /** * Form Tj = Tj */ resolve-implied-equality-constraint(|constraints, results) = ?Constraint(Equal(), t, t) ; !constraints /** * Form Tj = Tk, where k != j. * * @todo I think this equality should be recorded? * @todo Should equality constrains be rewritten? * @todo Should the lhs of the constraints be rewritten? */ resolve-implied-equality-constraint(|constraints, results) = ?Constraint(Equal(), tj, tk) ; where(not(<eq> (tj, tk))) ; where(<hashtable-get(|tk)> results) ; <map(Constraint(id, id, topdown( (tj -> tk) )))> constraints strategies /** * @todo Limit inference to remaining type variables? * @type List(Constraints) -> _ */ resolve-supertype-constaints(|typevars, results) = ?constraints ; <map( try({tv,type: ?tv ; <resolve-supertype-constaints(|tv)> constraints => type ; <hashtable-push-existing(|tv, type)> results }) )> typevars /** * @type List(Constraint) -> */ resolve-supertype-constaints(|typevar) = retain-all(?Constraint(SuperType(), tv, <id>)) ; not(?[]) ; lub strategies infer-unresolved-type-arguments = fail