From 713a313b06256a13ddefa5e257e3b80f8aa808ba Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 15:32:49 +0000 Subject: feat(codegen): convert implicitly between CHAR and STRING A CHAR becomes a one-character STRING in &, comparisons, assignment, parameter passing and RETURN. A STRING becomes a CHAR in assignment, parameter passing and RETURN, with a runtime error when its length is not 1. CHAR with INTEGER or BOOLEAN still does not convert. Co-Authored-By: Claude Sonnet 5.5 --- lib/CodeGen/OperatorGen.cc | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'lib/CodeGen/OperatorGen.cc') diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 0963e05..a840408 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -16,13 +16,26 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( auto Members = FuncGen->getOverloads(Left->Name + "." + operatorName(Op)); Candidates.insert(Candidates.end(), Members.begin(), Members.end()); } - for (const FuncSig *Sig : Candidates) { - bool Member = !Sig->Prototype->getOwnerClass().empty(); - if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue; - if (!Member && !Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; - if (Right && !Right->sameType(resolveType(Sig->Params[Member ? 0 : 1].TypeName))) continue; - if (Result.Signature) Result.Ambiguous = true; - else Result.Signature = Sig; + // An exact match wins; failing that, a CHAR operand may stand in for a + // STRING parameter (it is converted when the arguments are marshalled). + auto Accepts = [&](const TypeInfo *Actual, const std::string &Param, bool Lenient) { + const TypeInfo *Formal = resolveType(Param); + if (Actual->sameType(Formal)) return true; + return Lenient && Actual->Kind == TypeKind::Char && Formal && Formal->isString(); + }; + // Two CHARs compare as CHARs; only '&' always builds a STRING. + bool CanConvert = Right && (Op == '&' || Left->isString() || Right->isString()); + for (bool Lenient : {false, true}) { + if (Lenient && !CanConvert) break; + for (const FuncSig *Sig : Candidates) { + bool Member = !Sig->Prototype->getOwnerClass().empty(); + if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue; + if (!Member && !Accepts(Left, Sig->Params[0].TypeName, Lenient)) continue; + if (Right && !Accepts(Right, Sig->Params[Member ? 0 : 1].TypeName, Lenient)) continue; + if (Result.Signature) Result.Ambiguous = true; + else Result.Signature = Sig; + } + if (Result.Signature) break; } return Result; } -- cgit v1.3.1-4-g156e