The general coercion operator, also known as double match, has the form
(<exp> : <subtype> :> <type>)
The <subtype> type can sometimes be omitted, in which case it is called one coercion. Therefore, in your case, the correct enforcement should look like this:
let a : tfull = (f_link : f_link_type :> tfull)
where f_link_type is the type of the f_link function.
The reason this can happen is described in the manual :
The former statement sometimes cannot force the expression expr from type typ1 to type typ2, even if type typ1 is a subtype of type typ2: in the current implementation, it only extends two levels of the abbreviation type containing objects and / or polymorphic variants, preserving only recursion when it is explicit in class type (for objects). As an exception to the above algorithm, if both the alleged type of the expression and the type are terrestrial (i.e., do not contain type variables), the first operator behaves like the last, taking the proposed type of expression as typ1. In case of failure with the former operator, the latter should be used.
Let me try to bring it to simpler words. Coercion is possible only if both the domain and the code are known. However, in many cases, you can apply a heuristic that will infer the domain from the codename and the current type of expression. This heuristic works if the type of expression is based on the earth, has no recursions and some other restrictions. In principle, if the domain type does not have a unique most general type, we need to list all possible generalizations and check all possible combinations.
source share