Box or unbox a value to another type iff a C type conversion is needed

ENSURE: result.mtype.ctype == mtype.ctype

Property definitions

nitc $ AbstractCompilerVisitor :: autobox
	# Box or unbox a value to another type iff a C type conversion is needed
	# ENSURE: `result.mtype.ctype == mtype.ctype`
	fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
src/compiler/abstract_compiler.nit:1488,2--1490,79

nitc $ SeparateCompilerVisitor :: autobox
	redef fun autobox(value, mtype)
	do
		if value.mtype == mtype then
			return value
		else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
			return value
		else if not value.mtype.is_c_primitive then
			if mtype.is_tagged then
				if mtype.name == "Int" then
					return self.new_expr("(long)({value})>>2", mtype)
				else if mtype.name == "Char" then
					return self.new_expr("(uint32_t)((long)({value})>>2)", mtype)
				else if mtype.name == "Bool" then
					return self.new_expr("(short int)((long)({value})>>2)", mtype)
				else
					abort
				end
			end
			return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
		else if not mtype.is_c_primitive then
			assert value.mtype == value.mcasttype
			if value.mtype.is_tagged then
				var res
				if value.mtype.name == "Int" then
					res = self.new_expr("(val*)({value}<<2|1)", mtype)
				else if value.mtype.name == "Char" then
					res = self.new_expr("(val*)((long)({value})<<2|2)", mtype)
				else if value.mtype.name == "Bool" then
					res = self.new_expr("(val*)((long)({value})<<2|3)", mtype)
				else
					abort
				end
				# Do not loose type info
				res.mcasttype = value.mcasttype
				return res
			end
			var valtype = value.mtype.as(MClassType)
			if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "CString" then
				valtype = compiler.mainmodule.pointer_type
			end
			var res = self.new_var(mtype)
			# Do not loose type info
			res.mcasttype = value.mcasttype
			self.require_declaration("BOX_{valtype.c_name}")
			self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
			return res
		else if (value.mtype.ctype == "void*" and mtype.ctype == "void*") or
			(value.mtype.ctype == "char*" and mtype.ctype == "void*") or
			(value.mtype.ctype == "void*" and mtype.ctype == "char*") then
			return value
		else
			# Bad things will appen!
			var res = self.new_var(mtype)
			self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
			self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
			return res
		end
	end
src/compiler/separate_compiler.nit:1293,2--1350,4

nitc $ GlobalCompilerVisitor :: autobox
	redef fun autobox(value, mtype)
	do
		if value.mtype == mtype then
			return value
		else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
			return value
		else if not value.mtype.is_c_primitive then
			return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
		else if not mtype.is_c_primitive then
			var valtype = value.mtype.as(MClassType)
			var res = self.new_var(mtype)
			if not compiler.runtime_type_analysis.live_types.has(valtype) then
				self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
				self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
				return res
			end
			self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
			return res
		else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then
			return value
		else
			# Bad things will appen!
			var res = self.new_var(mtype)
			self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
			self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
			return res
		end
	end
src/compiler/global_compiler.nit:338,2--365,4