Java Reference
In-Depth Information
argument
U
in any way. It is a supertype of
G
<
X
>
for every
X
that is a valid
type argument to
G
. No meaningful constraint on
U
can be derived from
A
.
♦ If
A
is an invocation of a generic type declaration
H
, where
H
is either
G
or su-
perclass or superinterface of
G
, then:
If
H
≠
G
, then let
S
1
, ...,
S
n
be the type parameters of
G
, and let
H
<
U
1
, ...,
U
l
>
be the unique invocation of
H
that is a supertype of
G
<
S
1
, ...,
S
n
>
, and let
V
=
H
<
U
1
, ...,
U
l
>[
S
k
=
U
]
. Then, if
V
:>
F
this algorithm is applied recursively to
the constraint
A
>>
V
.
Our goal here is to simplify the relationship between
A
and
F
. We aim to re-
cursively invoke the algorithm on a simpler case, where the type argument is
known to be an invocation of the same generic type declaration as the formal.
Let's consider the case where both
H
and
G
have only a single type argument.
Since we have the constraint
A
=
H
<
X
>
>>
F
=
G
<
U
>
, where
H
is distinct from
G
, it must be the case that
H
is some proper superclass or superinterface of
G
. There must be a (non-wildcard) invocation of
H
that is a supertype of
F
=
G
<
U
>
. Call this invocation
V
.
If we replace
F
by
V
in the constraint, we will have accomplished the goal of
relating two invocations of the same generic (as it happens,
H
).
How do we compute
V
? The declaration of
G
must introduce a type parameter
S
, and there must be some (non-wildcard) invocation of
H
,
H
<
U
1
>
, that is a
supertype of
G
<
S
>
. Substituting the type expression
U
for
S
will then yield a
(non-wildcard) invocation of
H
,
H
<
U
1
>[
S
=
U
]
, that is a supertype of
G
<
U
>
. For
example, in the simplest instance,
U
1
might be
S
, in which case we have
G
<
S
>
<:
H
<
S
>
, and
G
<
U
> <:
H
<
U
>
=
H
<
S
>[
S
=
U
]
=
V
.
It may be the case that
H
<
U
1
>
is independent of
S
- that is,
S
does not occur
in
U
1
at all. However, the substitution described above is still valid - in this
situation,
V
=
H
<
U
1
>[
S
=
U
]
=
H
<
U
1
>
. Furthermore, in this circumstance,
G
<
T
>
<:
H
<
U
1
>
for any
T
, and in particular
G
<
U
> <:
H
<
U
1
>
=
V
.
Regardless of whether
U
1
depends on
S
, we have determined the type
V
, the
invocation of
H
that is a supertype of
G
<
U
>
. We can now invoke the algorithm
recursively on the constraint
H
<
X
>
=
A
>>
V
=
H
<
U
1
>[
S
=
U
]
. We will then be
able to relate the type arguments of both invocations of
H
and extract the rel-
evant constraints from them.
Otherwise, if
A
is of the form
G
<
...,
X
k-1
,
W
,
X
k+1
, ...
>
, where
W
is a type ex-
pression, this algorithm is applied recursively to the constraint
W
=
U
.