diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 15:32:49 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 15:32:49 +0000 |
| commit | 713a313b06256a13ddefa5e257e3b80f8aa808ba (patch) | |
| tree | 0288e9e9e44b9765cf2285fa3adaf82963612180 /lib/CodeGen/OperatorGen.cc | |
| parent | 5a5a14be5e2683a42906da4b2ad19690e230c871 (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/OperatorGen.cc')
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 27 |
1 files changed, 20 insertions, 7 deletions
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; } |
