# Generate a Nit "is" for two runtime_variables
fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
src/compiler/abstract_compiler.nit:1503,2--1504,77
redef fun equal_test(value1, value2)
do
var res = self.new_var(bool_type)
if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
var tmp = value1
value1 = value2
value2 = tmp
end
if value1.mtype.is_c_primitive then
var t1 = value1.mtype
assert t1 == value1.mcasttype
# Fast case: same C type.
if value2.mtype == t1 then
# Same exact C primitive representation.
self.add("{res} = {value1} == {value2};")
return res
end
# Complex case: value2 has a different representation
# Thus, it should be checked if `value2` is type-compatible with `value1`
# This compatibility is done statically if possible and dynamically else
# Conjunction (ands) of dynamic tests according to the static knowledge
var tests = new Array[String]
var t2 = value2.mcasttype
if t2 isa MNullableType then
# The destination type cannot be null
tests.add("({value2} != NULL)")
t2 = t2.mtype
else if t2 isa MNullType then
# `value2` is known to be null, thus incompatible with a primitive
self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
return res
end
if t2 == t1 then
# Same type but different representation.
else if t2.is_c_primitive then
# Type of `value2` is a different primitive type, thus incompatible
self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
return res
else if t1.is_tagged then
# To be equal, `value2` should also be correctly tagged
tests.add("({extract_tag(value2)} == {t1.tag_value})")
else
# To be equal, `value2` should also be boxed with the same class
self.require_declaration("class_{t1.c_name}")
tests.add "({class_info(value2)} == &class_{t1.c_name})"
end
# Compare the unboxed `value2` with `value1`
if tests.not_empty then
self.add "if ({tests.join(" && ")}) \{"
end
self.add "{res} = {self.autobox(value2, t1)} == {value1};"
if tests.not_empty then
self.add "\} else {res} = 0;"
end
return res
end
var maybe_null = true
var test = new Array[String]
var t1 = value1.mcasttype
if t1 isa MNullableType then
test.add("{value1} != NULL")
t1 = t1.mtype
else
maybe_null = false
end
var t2 = value2.mcasttype
if t2 isa MNullableType then
test.add("{value2} != NULL")
t2 = t2.mtype
else
maybe_null = false
end
var incompatible = false
var primitive
if t1.is_c_primitive then
primitive = t1
if t1 == t2 then
# No need to compare class
else if t2.is_c_primitive then
incompatible = true
else if can_be_primitive(value2) then
if t1.is_tagged then
self.add("{res} = {value1} == {value2};")
return res
end
if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
test.add("(!{extract_tag(value2)})")
end
test.add("{value1}->class == {value2}->class")
else
incompatible = true
end
else if t2.is_c_primitive then
primitive = t2
if can_be_primitive(value1) then
if t2.is_tagged then
self.add("{res} = {value1} == {value2};")
return res
end
if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
test.add("(!{extract_tag(value1)})")
end
test.add("{value1}->class == {value2}->class")
else
incompatible = true
end
else
primitive = null
end
if incompatible then
if maybe_null then
self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
return res
else
self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
return res
end
end
if primitive != null then
if primitive.is_tagged then
self.add("{res} = {value1} == {value2};")
return res
end
test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
else if can_be_primitive(value1) and can_be_primitive(value2) then
if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
test.add("(!{extract_tag(value1)}) && (!{extract_tag(value2)})")
end
test.add("{value1}->class == {value2}->class")
var s = new Array[String]
for t, v in self.compiler.box_kinds do
if t.mclass_type.is_tagged then continue
s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
end
if s.is_empty then
self.add("{res} = {value1} == {value2};")
return res
end
test.add("({s.join(" || ")})")
else
self.add("{res} = {value1} == {value2};")
return res
end
self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
return res
end
src/compiler/separate_compiler.nit:1985,2--2139,4
redef fun equal_test(value1, value2)
do
var res = self.new_var(bool_type)
if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
var tmp = value1
value1 = value2
value2 = tmp
end
if value1.mtype.is_c_primitive then
if value2.mtype == value1.mtype then
self.add("{res} = {value1} == {value2};")
else if value2.mtype.is_c_primitive then
self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
else
var mtype1 = value1.mtype.as(MClassType)
self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
self.add("if ({res}) \{")
self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
self.add("\}")
end
else
var s = new Array[String]
for t in self.compiler.live_primitive_types do
if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
end
if self.compiler.mainmodule.model.get_mclasses_by_name("Pointer") != null then
var pointer_type = self.compiler.mainmodule.pointer_type
if value1.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) or
value2.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) then
s.add "(((struct {pointer_type.c_name}*){value1})->value == ((struct {pointer_type.c_name}*){value2})->value)"
end
end
if s.is_empty then
self.add("{res} = {value1} == {value2};")
else
self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
end
end
return res
end
src/compiler/global_compiler.nit:948,2--991,4