aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/OperatorGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 15:32:49 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 15:32:49 +0000
commit713a313b06256a13ddefa5e257e3b80f8aa808ba (patch)
tree0288e9e9e44b9765cf2285fa3adaf82963612180 /lib/CodeGen/OperatorGen.cc
parent5a5a14be5e2683a42906da4b2ad19690e230c871 (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.cc27
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;
}