Class GenericAssignability


  • public final class GenericAssignability
    extends Object
    Bigger-picture, method-level static methods.

    Whereas the methods of Types answer questions like "does this type assign to that type", whereas this class's methods address questions like "does this set of method arguments assign to this set of method parameters given shared type variables?"

    Author:
    Gabriel Selzer
    • Method Detail

      • checkGenericAssignability

        public static boolean checkGenericAssignability​(Type src,
                                                        ParameterizedType dest,
                                                        boolean safeAssignability)
        Parameters:
        src - the type for which assignment should be checked from
        dest - the parameterized type for which assignment should be checked to
        safeAssignability - used to determine if we want to check if the src→dest assignment would be safely assignable even though it would cause a compiler error if we explicitly tried to do this (useful pretty much only for Op matching)
        Returns:
        whether and assignment of source to destination would be a legal java statement
      • checkGenericAssignability

        public static boolean checkGenericAssignability​(Type src,
                                                        ParameterizedType dest,
                                                        Map<TypeVariable<?>,​Type> typeVarAssigns,
                                                        boolean safeAssignability)
        Checks whether it would be legal to assign the Type source to the specified ParameterizedType destination (which could possibly be a supertype of the source type). Thereby, possible TypeVariables contained in the parameters of the source are tried to be inferred in the sense of empty angle brackets when a new object is created:
        
         List<Integer> listOfInts = new ArrayList<>();
         
        Hence, the types to put between the brackets are tried to be determined. Inference will be done by simple matching of an encountered TypeVariable in the source to the corresponding type in the parameters of the destination. If an TypeVariable is encountered more than once, the corresponding type in the destination needs to perfectly match. Else, false will be returned.

        Examples:

        If we have a class:
         class NumberSupplier<M extends Number> implements Supplier<M>
         
        The following check will return true:
         checkGenericAssignability(NumberSupplier.class,
                new Nil<Supplier<Double>>()
                {}.type())
         
        Which will check if the following assignment would be legal:
         Supplier<Double> list = new NumberSupplier<>()
         
        Here, the parameter <M extends Number> can be inferred to be of type Double from the type Supplier<Double>

        Consequently the following will return false:

         checkGenericAssignability(NumberSupplier.class,
                new Nil<Supplier<String>>() {}.type())
         
        <M extends Number> can't be inferred, as type String is not within the bounds of M.

        Furthermore, the following will return false for: class NumberFunc<M extends Number> implements Function<M, M>:

         checkGenericAssignability(NumberSupplier.class,
                new Nil<Function<Double, Integer>>() {}.type())
         
        <M extends Number> can't be inferred, as types Double and Integer are ambiguous for M.
        Parameters:
        src - the type for which assignment should be checked from
        dest - the parameterized type for which assignment should be checked to
        typeVarAssigns - the map of TypeVariables to Types to populate with what would occur in this scenario; must be empty or null
        safeAssignability - used to determine if we want to check if the src→dest assignment would be safely assignable even though it would cause a compiler error if we explicitly tried to do this (useful pretty much only for Op matching)
        Returns:
        whether and assignment of source to destination would be a legal java statement
      • inferTypeVariables

        public static Map<TypeVariable<?>,​Type> inferTypeVariables​(Type type,
                                                                         Type inferFrom)
        Tries to infer type vars contained in types from corresponding types from inferFrom, putting them into the specified map. When a TypeInferenceException is thrown, the caller should assume that some of the mappings within typeMappings are incorrect.
        Parameters:
        type -
        inferFrom -
        Returns:
        the mapping of TypeVariables in type to Types in inferFrom
      • inferTypeVariables

        public static void inferTypeVariables​(Type[] types,
                                              Type[] inferFroms,
                                              Map<TypeVariable<?>,​Type> typeVarAssigns)
        Tries to infer type vars contained in types from corresponding types from inferFrom, putting them into the specified map. When a TypeInferenceException is thrown, the caller should assume that some of the mappings within typeMappings are incorrect.
        Parameters:
        types - - the types containing TypeVariables
        inferFroms - - the types used to infer the TypeVariables within types
        typeVarAssigns - - the mapping of TypeVariables to Types
      • isSafeAssignable

        public static boolean isSafeAssignable​(Type[] destTypes,
                                               Map<TypeVariable<?>,​Type> typeVarAssigns,
                                               Type src,
                                               Type dest)
        We know that the special types for the Op candidate and what we asked for are the same (i.e. that we are trying to determine if one Function can be assigned to another Function). There are some situations (that are particularly common when using ops.run()) where the Function SHOULD NOT NORMALLY MATCH UP but WE KNOW IT WILL BE SAFE TO ASSIGN. This method attempts to tease those situations out as a last resort.
        Parameters:
        destTypes - - the array of Parameterized types of the OpInfo we called the matcher on (in the case of ops.run(), it is a Type array of the types of the args we passed through.)
        typeVarAssigns - - a Map of all of the Type Variables already determined.
        dest - - the special type of the Op that we want to find a match for (determined by the user / ops.run())
        Returns:
        boolean - true if we can safely match this Op even though the types do not directly match up. False otherwise.
      • mapVarToTypes

        public static Type[] mapVarToTypes​(Type[] typesToMap,
                                           Map<TypeVariable<?>,​Type> typeAssigns)
        Map type vars in specified type list to types using the specified map. In doing so, type vars mapping to other type vars will not be followed but just replaced.
        Parameters:
        typesToMap -
        typeAssigns -
        Returns:
        a copy of typesToMap in which the TypeVariables (that are present in typeAssigns) are mapped to the associated values within the Map.