Returns true if the test concern real generic covariance
# Common method used when static subtype test is performed by a phase
# Returns true if the test concern real generic covariance
fun count_types(node, elem: ANode, sub, sup: MType, mmodule: MModule, anchor: nullable MClassType): Bool
do
sub = sub.undecorate
sup = sup.undecorate
# Category of the target type
if sub isa MGenericType then
cpt_subtype_kinds.inc("generic type")
else if not sub isa MClassType then
cpt_subtype_kinds.inc("formal type")
else if sub.mclass.kind == enum_kind then
cpt_subtype_kinds.inc("primitive type")
else if sub.mclass.name == "Object" then
cpt_subtype_kinds.inc("object")
else
cpt_subtype_kinds.inc("non-generic type")
end
# Class of the subtype
if sub isa MClassType then
cpt_total_classes.inc(sub.mclass.to_s)
else
cpt_total_classes.inc(sub.to_s)
end
# Equal monomorph case
if sub == sup then
cpt_total_variance.inc("monomorph")
return false
end
# Equivalent monomorph case
if sub.is_subtype_invar(mmodule, anchor, sup) and sup.is_subtype_invar(mmodule, anchor, sub) then
cpt_total_variance.inc("monomorph equiv")
return false
end
# Formal case
if not sub isa MClassType then
cpt_total_variance.inc("polymorph & formal")
return false
end
# Non generic case
if not sub isa MGenericType then
cpt_total_variance.inc("polymorph & non-generic")
return false
end
# Invariant case
if sub.is_subtype_invar(mmodule, anchor, sup) then
cpt_total_variance.inc("polymorph & generic & invariant")
return false
end
if sub.is_subtype(mmodule, anchor, sup) then
# Covariant
cpt_total_variance.inc("polymorph & generic & covariant")
else
# Cast (explicit or autocast)
if sup.is_subtype(mmodule, anchor, sub) then
cpt_total_variance.inc("polymorph & generic & upcast!?")
cpt_pattern.inc("7.upcast")
return false
end
if not sup isa MGenericType then
cpt_total_variance.inc("polymorph & generic & lateral-cast from non-gen")
return false
end
cpt_total_variance.inc("polymorph & generic & lateral-cast from gen")
end
## ONLY covariance remains here
cpt_modules.inc(mmodule.mgroup.mpackage.name)
cpt_classes.inc(sub.mclass)
# Track if `cpt_explanations` is already decided (used to fallback on unknown)
var caseknown = false
# Detect the pattern
var n = node
while n isa AType or n isa AExprs do n = n.parent.as(not null)
cpt_nodes.inc(n.class_name)
if n isa AVarAssignExpr or n isa AAttrPropdef and elem isa AExpr then
cpt_pattern.inc("1.assign")
else if n isa ASendExpr or n isa ANewExpr then
cpt_pattern.inc("2.param")
else if n isa AReturnExpr then
cpt_pattern.inc("3.return")
else if n isa APropdef or n isa ASignature then
cpt_pattern.inc("4.redef")
else if n isa AAsCastExpr or n isa AIsaExpr then
cpt_pattern.inc("6.downcast")
if n isa AIsaExpr and n.n_expr isa ASelfExpr then
cpt_explanations.inc("downcast on self")
caseknown = true
else
node.debug("6.downcast {sup} to {sub}")
end
else if n isa ASuperPropdef then
cpt_pattern.inc("8.subclass")
else if n isa AArrayExpr then
cpt_pattern.inc("9.array element")
else
n.debug("Unknown pattern")
cpt_pattern.inc("X.unknown")
end
if not caseknown then
if false then
cpt_explanations.inc("covariant class")
else
cpt_explanations.inc("other covariance")
end
end
return true
end
src/metrics/detect_covariance.nit:129,2--251,4