/**
* 15.12.2.7: Inferring Type Arguments based on Actual Arguments
*
* @author Martin Bravenboer
*/
module dryad/jls/types/Lub
imports
dryad/jls/types/Erasure
strategies
/**
* @todo Handle infinite types.
* @type List(Type) -> Type
*/
lub =
lub-ST-MEC => (st, mec)
; where(<iset-elements> st => supertypes)
; <iset-elements> mec
; map(lub-Candidate(|supertypes))
; if ?[t] then
!t
else
!IntersectionType(<id>)
end
/**
* @type List(Type) -> (IndexedSet(Type), IndexedSet(Type))
*/
lub-ST-MEC =
where(new-iset => st)
// Fill ST and create list of EST sets
; map({est:
where(new-iset => est)
; lub-ST-EST(|st, est)
; !est
})
// Intersection of EST lists: EC
; ?[ec | est-list]
; <foldl(iset-isect | est-list)> ec
// EC to MEC
// @todo This is a very expensive implementation. Sorting might help.
; <iset-elements> ec
; map({t: ?t; <iset-remove-all(is-proper-supertype(|t))> ec })
; !ec => mec
; !(st, mec)
/**
* Returns the set of (erased) super types (ST and EST).
*
* @param IndexedSet(Type)
* @type Type -> List(Type)
*/
lub-ST-EST(|st, est) =
where(
supertypes => list
; <iset-addlist(|list)> st
; <map({t: type-erasure => t; <iset-add(|t)> est})> list
)
strategies
/**
* @type List(Type) -> IndexedSet(Type)
*/
lub-MEC =
lub-ST-MEC => (_, <id>)
strategies
/**
* @param List(Type)
* @type Type -> List(Type)
*/
lub-Inv(|supertypes) =
?g
; (?ClassType(tn, _) + ?InterfaceType(tn, _))
; <retain-all(?ClassType(tn, Some(_)) + ?InterfaceType(tn, Some(_)))> supertypes
lub-CandidateInvocation(|supertypes) =
?g
; <lub-Inv(|supertypes)> g
// ; debug(!"Inv: ------------- ")
; lub-lci
/**
* @todo Member types: tn can be type.
*/
lub-Candidate(|supertypes) =
?w
// ; debug(!"Candidate: ------------- ")
; if (?ClassType(tn, _) + ?InterfaceType(tn, _))
; <lookup-class> tn
; is-generic
then
lub-CandidateInvocation(|supertypes)
else
id
end
/**
* lci.
*
* @todo This seems to be a fold.
*/
strategies
lub-lci =
?[e1, e2, e3 | es]
; <lub-lci> [<lub-lci> [e1, e2], e3 | es]
lub-lci :
[ClassType(tn, Some(TypeArgs(ts1))), ClassType(tn, Some(TypeArgs(ts2)))]
->
ClassType(tn, Some(TypeArgs(ts3)))
where
<zip(lub-lcta)> (ts1, ts2) => ts3
lub-lci :
[InterfaceType(tn, Some(TypeArgs(ts1))), InterfaceType(tn, Some(TypeArgs(ts2)))]
->
InterfaceType(tn, Some(TypeArgs(ts3)))
where
<zip(lub-lcta)> (ts1, ts2) => ts3
/**
* @todo This (trivial) case seems to be missing in the JLS. Report.
*/
lub-lci =
?[<id>]
/**
* lcta.
*
* @todo Wildcard alternatives
*/
strategies
lub-lcta :
(u, u) -> u
where
<is-type-expression> u
lub-lcta :
(u, v) -> Wildcard(opt-upper)
where
not(<eq> (u, v))
; <is-type-expression> u
; <is-type-expression> v
; <lub> [u, v] => upper
; if !upper => TypeObject() then
!None()
else
!Some(WildcardUpperBound(upper))
end
; ?opt-upper
/**
* @todo Implement: simple is-Type should be enough?
*/
is-type-expression =
not(?Wildcard(_))
strategies
/**
* Removes all elements from set that satisfy s.
*
* @type IndexedSet -> IndexedSet
*/
iset-remove-all(s) =
?set
; where(
iset-elements
; map({x: ?x; (s < <iset-remove(|x)> set + id)})
)