Generic method type inference when the target type has a wildcard

后端 未结 2 1724
野趣味
野趣味 2021-01-16 05:49

I understand that the compiler uses the target type to determine the type argument that makes the generic method invocation applicable. For instance, in the following statem

2条回答
  •  攒了一身酷
    2021-01-16 06:25

    Each usage of a wildcard has a distinct type associated with it. (Usually the JLS refers to this as being a "fresh type".) This is how for example a compiler error like this works:

    List list0 = ... ;
    List list1 = ... ;
    list0.add(list1.get(0)); // error
    

    Because it's the case that list0 and list1 are given separate types by the compiler such that for the most part

    reference_type_of(List) != reference_type_of(List)
    

    You can begin to see how this fits in to type inference if you try something like

    {
        List list0 = ... ;
        List list1 = ... ;
        test(list0, list1);
    }
    static  void test(List list0, List list1) {}
    

    Where the compiler emits an error that actually tells us a little bit about the types that it has generated for list0 and list1.

    error: method test in class Ideone cannot be applied to given types;
        test(list0, list1);
        ^
      required: List,List
      found: List,List
      reason: no instance(s) of type variable(s) T exist so that
              argument type List conforms to formal parameter type List
      where T is a type-variable:
        T extends Object declared in method test(List,List)
      where CAP#1,CAP#2 are fresh type-variables:
        CAP#1 extends Object from capture of ?
        CAP#2 extends Object from capture of ?
    

    (My emphasis in bold.) These CAP#... types were generated during capture conversion. What it's showing us is that when the method invocation expression was examined, list0 and list1 were given distinct types from each other. (And for those that need an explanation for the error: it's because the declaration of test asserts that both Lists must have the same T.)

    So since we now know that a wildcard gets associated a reference type, we can see that in a case like

    List empty = Collections.emptyList();
    

    The invocation will be inferred as something like "a fresh type where the upper bound is Object". Or symbolically we could say the compiler might see something like

    // target type       -->       inferred invocation type
    //     v                           v
    List empty = Collections.emptyList();
    

    Although: of course we are always guessing a little bit because it's up to the compiler how it implements this. In theory, for a case like the above trivial assignment of emptyList(), it would not have to do work to generate the correct bytecode.

    Also, I am sorry, I don't feel like spec scouring today. Essentially the type inference here works by generating a set of constraints to demonstrate that the method invocation should or should not compile. The algorithm described in 18.5.2 incorporates a wildcard in this way.

提交回复
热议问题