<commit_before>#include "instanciate.h"
#include "details/reporting/report.h"
#include "details/reporting/message.h"
#include "details/utils/origin.h"
#include "details/pass/d-object-map/mapping.h"
#include "libnanyc-traces.h"
#include "instanciate-atom.h"
#include "instanciate-debug.h"
#include "instanciate-error.h"
#include <memory>
#include "details/pass/e-instanciate/ref-unref.h"

using namespace Yuni;


namespace ny {
namespace Pass {
namespace Instanciate {


namespace {


void prepareSignature(Signature& signature, InstanciateData& info) {
	uint32_t count = static_cast<uint32_t>(info.params.size());
	if (count != 0) {
		signature.parameters.resize(count);
		for (uint32_t i = 0; i != count; ++i) {
			assert(info.params[i].cdef != nullptr);
			auto& cdef  = *(info.params[i].cdef);
			auto& param = signature.parameters[i];
			param.kind = cdef.kind;
			param.qualifiers = cdef.qualifiers;
			if (param.kind == nyt_any)
				param.atom = const_cast<Atom*>(info.cdeftable.findClassdefAtom(cdef));
			assert(param.kind != nyt_any or param.atom != nullptr);
		}
	}
	count = static_cast<uint32_t>(info.tmplparams.size());
	if (count != 0) {
		signature.tmplparams.resize(count);
		for (uint32_t i = 0; i != count; ++i) {
			assert(info.tmplparams[i].cdef != nullptr);
			auto& cdef  = *(info.tmplparams[i].cdef);
			auto& param = signature.tmplparams[i];
			param.atom = const_cast<Atom*>(info.cdeftable.findClassdefAtom(cdef));
			param.kind = cdef.kind;
			param.qualifiers = cdef.qualifiers;
			assert(param.kind != nyt_any or param.atom != nullptr);
		}
	}
}


bool makeNewAtomInstanciation(InstanciateData& info, Atom& atom) {
	// create a new atom with non-generic parameters / from a contextual atom
	// (generic or anonymous class) and re-map from the parent
	{
		auto& sequence  = *atom.opcodes.sequence;
		auto& originaltable = info.cdeftable.originalTable();
		Mutex mutex; // useless but currently required for the first pass by SequenceMapping
		Pass::Mapping::SequenceMapping mapper{originaltable, mutex, sequence};
		mapper.evaluateWholeSequence = false;
		mapper.prefixNameForFirstAtomCreated = "^"; // not an user-defined atom
		mapper.map(*atom.parent, atom.opcodes.offset);
		if (unlikely(!mapper.firstAtomCreated))
			return (error() << "failed to remap atom '" << atom.caption() << '\'');
		assert(info.atom.get().atomid != mapper.firstAtomCreated->atomid);
		assert(&info.atom.get() != mapper.firstAtomCreated);
		info.atom = std::ref(*mapper.firstAtomCreated);
	}
	auto& newAtom = info.atom.get();
	newAtom.tmplparamsForPrinting.swap(newAtom.tmplparams);
	newAtom.classinfo.isInstanciated = true;
	info.shouldMergeLayer = true;
	return resolveStrictParameterTypes(info.build, newAtom, &info);
}


//! Prepare the first local registers from the parameter types
void substituteParameterTypes(ClassdefTableView& cdeftable, Atom& atom, const Signature& signature) {
	// magic constant +2
	//  * +1: all clid are 1-based (0 is reserved for the atom itself, not for an internal var)
	//  * +1: the CLID{X, 1} is reserved for the return type
	cdeftable.addSubstitute(nyt_void, nullptr, Qualifiers()); // unused, since 1-based
	auto& rettype = cdeftable.rawclassdef(CLID{atom.atomid, 1}); // return type
	Atom* retAtom = (not rettype.isBuiltinOrVoid()) ? cdeftable.findRawClassdefAtom(rettype) : nullptr;
	cdeftable.addSubstitute(rettype.kind, retAtom, rettype.qualifiers);
	auto substitute = [&](auto & parameter) {
		cdeftable.addSubstitute(parameter.kind, parameter.atom, parameter.qualifiers);
		assert(parameter.kind != nyt_any or parameter.atom != nullptr);
	};
	uint32_t count = signature.parameters.size();
	for (uint32_t i = 0; i != count; ++i)
		substitute(signature.parameters[i]);
	for (uint32_t i = 0; i != count; ++i) // + reserved for cloning parameters
		substitute(signature.parameters[i]);
	count = signature.tmplparams.size();
	for (uint32_t i = 0; i != count; ++i)
		substitute(signature.tmplparams[i]);
}


ir::Sequence* translateAndInstanciateASTIRCode(InstanciateData& info, Signature& signature) {
	auto& atomRequested = info.atom.get();
	if (unlikely(!atomRequested.opcodes.sequence or !atomRequested.parent)) {
		ice() << "invalid atom";
		return nullptr;
	}
	// In case or an anonymous class or a class with generic type parameters, it is
	// necessary to use new atoms (t needs a forked version to work on to have different types)
	if (atomRequested.isContextual()) {
		if (not makeNewAtomInstanciation(info, atomRequested))
			return nullptr;
		assert(&info.atom.get() != &atomRequested and "a new atom must be used");
	}
	auto& atom = info.atom.get(); // current atom, can be different from `atomRequested`
	if (!!atom.candidatesForCapture and info.parent)
		info.parent->captureVariables(atom);
	Atom::FlagAutoSwitch<Atom::Flags::instanciating> flagUpdater{atom};<commit_msg>instanciation: rename duplicateAtomForSpecialization<commit_after>#include "instanciate.h"
#include "details/reporting/report.h"
#include "details/reporting/message.h"
#include "details/utils/origin.h"
#include "details/pass/d-object-map/mapping.h"
#include "libnanyc-traces.h"
#include "instanciate-atom.h"
#include "instanciate-debug.h"
#include "instanciate-error.h"
#include <memory>
#include "details/pass/e-instanciate/ref-unref.h"

using namespace Yuni;


namespace ny {
namespace Pass {
namespace Instanciate {


namespace {


void prepareSignature(Signature& signature, InstanciateData& info) {
	uint32_t count = static_cast<uint32_t>(info.params.size());
	if (count != 0) {
		signature.parameters.resize(count);
		for (uint32_t i = 0; i != count; ++i) {
			assert(info.params[i].cdef != nullptr);
			auto& cdef  = *(info.params[i].cdef);
			auto& param = signature.parameters[i];
			param.kind = cdef.kind;
			param.qualifiers = cdef.qualifiers;
			if (param.kind == nyt_any)
				param.atom = const_cast<Atom*>(info.cdeftable.findClassdefAtom(cdef));
			assert(param.kind != nyt_any or param.atom != nullptr);
		}
	}
	count = static_cast<uint32_t>(info.tmplparams.size());
	if (count != 0) {
		signature.tmplparams.resize(count);
		for (uint32_t i = 0; i != count; ++i) {
			assert(info.tmplparams[i].cdef != nullptr);
			auto& cdef  = *(info.tmplparams[i].cdef);
			auto& param = signature.tmplparams[i];
			param.atom = const_cast<Atom*>(info.cdeftable.findClassdefAtom(cdef));
			param.kind = cdef.kind;
			param.qualifiers = cdef.qualifiers;
			assert(param.kind != nyt_any or param.atom != nullptr);
		}
	}
}


bool duplicateAtomForSpecialization(InstanciateData& info, Atom& atom) {
	// create a new atom with non-generic parameters / from a contextual atom
	// (generic or anonymous class) and re-map from the parent
	{
		auto& sequence  = *atom.opcodes.sequence;
		auto& originaltable = info.cdeftable.originalTable();
		Mutex mutex; // useless but currently required for the first pass by SequenceMapping
		Pass::Mapping::SequenceMapping mapper{originaltable, mutex, sequence};
		mapper.evaluateWholeSequence = false;
		mapper.prefixNameForFirstAtomCreated = "^"; // not an user-defined atom
		mapper.map(*atom.parent, atom.opcodes.offset);
		if (unlikely(!mapper.firstAtomCreated))
			return (error() << "failed to remap atom '" << atom.caption() << '\'');
		assert(info.atom.get().atomid != mapper.firstAtomCreated->atomid);
		assert(&info.atom.get() != mapper.firstAtomCreated);
		info.atom = std::ref(*mapper.firstAtomCreated);
	}
	auto& newAtom = info.atom.get();
	newAtom.tmplparamsForPrinting.swap(newAtom.tmplparams);
	newAtom.classinfo.isInstanciated = true;
	info.shouldMergeLayer = true;
	return resolveStrictParameterTypes(info.build, newAtom, &info);
}


//! Prepare the first local registers from the parameter types
void substituteParameterTypes(ClassdefTableView& cdeftable, Atom& atom, const Signature& signature) {
	// magic constant +2
	//  * +1: all clid are 1-based (0 is reserved for the atom itself, not for an internal var)
	//  * +1: the CLID{X, 1} is reserved for the return type
	cdeftable.addSubstitute(nyt_void, nullptr, Qualifiers()); // unused, since 1-based
	auto& rettype = cdeftable.rawclassdef(CLID{atom.atomid, 1}); // return type
	Atom* retAtom = (not rettype.isBuiltinOrVoid()) ? cdeftable.findRawClassdefAtom(rettype) : nullptr;
	cdeftable.addSubstitute(rettype.kind, retAtom, rettype.qualifiers);
	auto substitute = [&](auto & parameter) {
		cdeftable.addSubstitute(parameter.kind, parameter.atom, parameter.qualifiers);
		assert(parameter.kind != nyt_any or parameter.atom != nullptr);
	};
	uint32_t count = signature.parameters.size();
	for (uint32_t i = 0; i != count; ++i)
		substitute(signature.parameters[i]);
	for (uint32_t i = 0; i != count; ++i) // + reserved for cloning parameters
		substitute(signature.parameters[i]);
	count = signature.tmplparams.size();
	for (uint32_t i = 0; i != count; ++i)
		substitute(signature.tmplparams[i]);
}


ir::Sequence* translateAndInstanciateASTIRCode(InstanciateData& info, Signature& signature) {
	auto& atomRequested = info.atom.get();
	if (unlikely(!atomRequested.opcodes.sequence or !atomRequested.parent)) {
		ice() << "invalid atom";
		return nullptr;
	}
	// In case or an anonymous class or a class with generic type parameters, it is
	// necessary to use new atoms (t needs a forked version to work on to have different types)
	if (atomRequested.isContextual()) {
		if (not duplicateAtomForSpecialization(info, atomRequested))
			return nullptr;
		assert(&info.atom.get() != &atomRequested and "a new atom must be used");
	}
	auto& atom = info.atom.get(); // current atom, can be different from `atomRequested`
	if (!!atom.candidatesForCapture and info.parent)
		info.parent->captureVariables(atom);
	Atom::FlagAutoSwitch<Atom::Flags::instanciating> flagUpdater{atom};
{'fraction_non_alphanumeric': 0.1388860290332544, 'fraction_numerical': 0.006795016987542469, 'mean_word_length': 4.912355447352404, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3315805', 'n_tokens_mistral': 3466, 'n_tokens_neox': 3254, 'n_words': 769}