/**
* 15.12.2 Compile-Time Step 2: Determine Method Signature
*
* Locate methods that are accessible and applicable
* Descriptor: signature plus return type
*/
module dryad/type-check/invoke/StepSignature
imports
dryad/jls/names/AccessControl
dryad/jls/types/Subtyping
dryad/type-check/invoke/InferringTypeArguments
dryad/jls/conversions/MethodInvocationConversion
strategies
/**
* @type Expr -> (Method Object, List(Attribute))
*/
determine-method-signature(|type, class, fromclass) =
?invocation
; identify-potentially-applicable-methods(|class, fromclass)
; log(|Debug(), "Potentially applicable methods", <id>)
; if ?[] then
log(|Notice(), "No potentially applicable methods found for invocation.", invocation)
end
; ?[_ | _]
; select-applicable-methods(|type, invocation)
; log(|Debug(), "Applicable methods", <id>)
; if ?[] then
log(|Notice(), "No applicable methods found for invocation.", invocation)
end
; ?[_ | _]
; select-maximally-specific-methods
; log(|Debug(), "Maximally specific methods", <id>)
; if ?[_, _ | _] then
log(|Notice(), "Method invocation is ambiguous: multiple maximally specific methods are found.", <id>)
; log(|Notice(), "Picking the first option for now.", <id>)
end
; ?[<id> | _]
; is-chosen-method-appropiate
strategies
/**
* 15.12.2.1: Identify Potentially Applicable Methods.
*
* @todo Consider static imports (end of section). Are invocations rewritten
* earlier, or should they be handled here?
* @type Expression -> List(Method Object)
*/
identify-potentially-applicable-methods(|class, fromclass) =
?Invoke(method, args)
; where(
<dryad-tc-name-of-method> method => name
; <length> args => arity
; <dryad-tc-explicit-type-arguments-method; length> method => typearity
)
; <get-methods(|name)> class
; filter(
where(get-simple-name => name)
// Accessible check
; is-accessible-from(|fromclass)
// Arity of member is less or equal to the arity of the invocation.
; where(<leq> (<get-arity>, arity))
// - variable arity
// - same fixed arity
; where(
if is-fixed-arity-method then
get-arity => arity
else
<geq> (arity, <subt> (<get-arity>, 1))
end
)
)
// - same number of explicit type parameters
; if not(!typearity => 0) then
filter(
where(get-formal-type-parameters; length => typearity)
)
end
/**
* 15.12.2.2, 15.12.2.3, 15.12.2.4 Select Applicable Methods
*/
strategies
/**
* Might return an empty list
*/
select-applicable-methods(|type, invocation) =
map(!(<id>, <determine-ASU(|type, invocation)>)); (
filter({A, S, U:
?(<id>, (A, S, U))
; is-applicable-method-by-subtyping(|A, S, U)
})
; ?[_ | _]
<+ filter({A, S, U:
?(<id>, (A, S, U))
; is-applicable-method-by-method-invocation-conversion(|A, S, U)
})
; ?[_ | _]
<+ filter(is-applicable-variable-arity-method)
)
/**
* 15.12.2.2 Phase 1: Identify Matching Arity Methods Applicable by Subtyping
*/
strategies
/**
* Succeeds if this method is applicable by subtyping.
*
* @param Type: the type on which the invocation occurs.
* @param Expr: the method invocation
* @type Method Object -> (Method Object, List(Attribute))
*/
is-applicable-method-by-subtyping(|type, invocation) =
?method
; where(determine-ASU(|type, invocation) => (A, S, U))
; is-applicable-method-by-subtyping(|A, S, U)
is-applicable-method-by-subtyping(|A, S, U) =
?method
; where(
<zip({Ai, Si : ?(Ai, Si); <is-subtype(|Si)> Ai})> (A, S)
)
; !(<id>, <opt-attr-U(![])> U)
/**
* 15.12.2.3 Phase 2: Identify Matching Arity Methods Applicable by
* Method Invocation Conversion
*/
strategies
is-applicable-method-by-method-invocation-conversion(|type, invocation) =
?method
; where(determine-ASU(|type, invocation) => (A, S, U))
; is-applicable-method-by-method-invocation-conversion(|A, S, U)
/**
*
*/
is-applicable-method-by-method-invocation-conversion(|A, S, U) =
?method
; where(
<zip({Ai, Si :
?(Ai, Si)
; <method-invocation-conversion(|Si)> Ai
})> (A, S) => conversions
)
; !(<id>, [Conversions(conversions) | <opt-attr-U(![])> U])
/**
* Adds an attribute ActualTypeArgs if there are any.
*/
opt-attr-U(cont) =
if ?[] then
cont
else
![ActualTypeArgs(<id>) | <cont>]
end
/**
* 15.12.2.4 Phase 3: Identify Applicable Variable Arity Methods
*/
strategies
/**
* @todo Who cares.
*/
is-applicable-variable-arity-method =
fail
strategies
/**
* Returns the list of arguments of a method invocation.
*
* @type Expr -> List(Expr)
*/
get-arguments-of-invocation =
?Invoke(_, <id>)
strategies
/**
* @param Type: the type on which the invocation occurs.
* @param Expr: the method invocation
*/
determine-ASU(|type, invocation) =
?method
; <get-arguments-of-invocation> invocation => args
; <map(type-attr)> args => A
; <determine-actual-formal-parameter-types(|type, invocation)> method => (S, U)
; !(A, S, U)
/**
* Determines S1 ... Sn and U1 ... Up as specified in 15.12.2.2
*
* @returns Tuple (S, U)
* @param Actual method invocation.
* @type Method Object -> (List(Type), List(Type))
*/
determine-actual-formal-parameter-types(|type, invocation) =
?method
; if get-formal-type-parameters => [_ | _] then
<determine-actual-type-arguments(|type, invocation)> method => U
; <get-formal-parameter-types(|type)> method
; apply-type-substitution(|method, U) => S
; !(S, U)
else
!(<get-formal-parameter-types(|type)> method, [])
end
/**
* Determines U1 ... Up as specified in 15.12.2.2
*
* @param Actual method invocation.
* @param Invoke inference of type arguments.
* @type Method Object -> List(Type)
*/
determine-actual-type-arguments(|type, invocation) =
?method
; where(
!invocation
; ?Invoke(<id>, _)
; dryad-tc-explicit-type-arguments-method => targs
)
; if !targs => [] then
/**
* Infer the type arguments. Inference begins with an initial
* set of constaints. This initial set of constraints requires
* that the statically known types of the actual arguments can
* be converted to the formal parameters types of the method
* declaration by method invocation invocation conversion.
*/
arg-types := <get-arguments-of-invocation; map(type-attr)> invocation
; param-types := <get-formal-parameter-types(|type)> method
; initial-constraints :=
<zip(!Constraint(LeftRightConvertible(), <Fst>, <Snd>))> (arg-types, param-types)
; table := <infer-type-arguments(|initial-constraints)> method
; < get-formal-type-parameters
; map(type-param-to-type-variable(|method))
; map({tv: ?tv; <hashtable-get(|tv)> table; ?[<id>]})
> method
else
!targs
end
/**
* 15.12.2.5 Choosing the Most Specific Method
*/
strategies
/**
* @todo DRY-71
* @type List((Method Object, List(Attribute))) -> List((Method Object, List(Attribute)))
*/
select-maximally-specific-methods =
?methods
; filter({method:
?(method, _)
; where(
not(<fetch(?(<id>, _); is-strictly-more-specific(|method))> methods)
)
})
/**
* Succeeds if m1 is more specific than m2
*
* @todo Parameterized types
* @todo Variable arity methods
* @param Method Object
* @type Method Object -> Method Object
*/
is-more-specific(|m2) =
?m1
; where(
<get-formal-parameter-types> m1 => params1
; <get-formal-parameter-types> m2 => params2
; <zip({t1, t2: ?(t1, t2); <is-subtype(|t2)> t1})> (params1, params2)
)
/**
* Succeeds if m1 is strictly more specific than m2
*/
is-strictly-more-specific(|m2) =
?m1
; where(
<is-more-specific(|m2)> m1
; <not(is-more-specific(|m1))> m2
)
/**
* 15.12.2.6 Method Result Type
*/
strategies
/**
* Determines the result type of the chosen method.
*
* @param Type to which the method is applied
* @param Attributes. Must contain information on method invocation
* conversion and actual type arguments.
* @type Method -> Type
*/
determine-result-type(|invtype, attrs) =
?method
; <get-return-type(|invtype)> method
; ( ?Void()
<+ where(<was-unchecked-conversion-necessary> attrs)
; type-erasure
<+ where(<is-generic> method)
; where(<fetch-elem(?ActualTypeArgs(<id>))> attrs => A)
; apply-type-substitution(|method, A)
; capture-conversion
<+ capture-conversion
)
/**
* @type List(Attribute) -> List(Attribute)
*/
was-unchecked-conversion-necessary =
where(
fetch(
?Conversions(<id>)
; fetch(
?MethodInvocationConversion(<id>)
; fetch(
?UncheckedConversion(_, _)
)
)
)
)
/**
* 15.12.2.6 Method Throws Type
*/
strategies
/**
* 15.12.2.7 Inferring Type Arguments Based on Actual Arguments
*
* @todo Implement
*/
strategies
/**
* 15.12.2.8 Inferring Unresolved Type Arguments
*
* @todo Implement
*/
strategies