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/ConstructorGen.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/ConstructorGen.cc')
| -rw-r--r-- | lib/CodeGen/ConstructorGen.cc | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc index 286435e..e956f9d 100644 --- a/lib/CodeGen/ConstructorGen.cc +++ b/lib/CodeGen/ConstructorGen.cc @@ -22,9 +22,11 @@ Value *CodeGen::emitOwnedValue(ExprAST *Expr, const TypeInfo *Type, std::vector<size_t> &Transfers) { if (!Type || (!Type->IsClass && !containsString(Type))) return emitCoercedExpr(Expr, Type); const TypeInfo *Source = getExprTypeInfo(Expr); - if (!Source || !Source->sameType(Type)) return emitCoercedExpr(Expr, Type); + // A CHAR argument becomes a fresh STRING temporary, owned like any other. + bool FromChar = Source && Type->isString() && Source->Kind == TypeKind::Char; + if (!Source || (!Source->sameType(Type) && !FromChar)) return emitCoercedExpr(Expr, Type); Value *Value = nullptr; - if (isObjectLValue(Expr)) { + if (!FromChar && isObjectLValue(Expr)) { LValueInfo LV; const auto *Var = dynamic_cast<VariableExprAST *>(Expr); const auto *Symbol = Var ? getSymbolInfo(Var->getName()) : nullptr; @@ -172,8 +174,11 @@ void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const Symb } return; } - if (Info && Info->IsClass) { - auto Resolution = resolveOperator(tok_assign, Info, getExprTypeInfo(Expr)); + const TypeInfo *ExprType = getExprTypeInfo(Expr); + // A CHAR assigned to a STRING is converted first, not bound to OPERATOR<-. + bool CharToString = Info && Info->isString() && ExprType && ExprType->Kind == TypeKind::Char; + if (Info && Info->IsClass && !CharToString) { + auto Resolution = resolveOperator(tok_assign, Info, ExprType); if (Resolution.Ambiguous) { reportError("Ambiguous assignment operator"); return; @@ -190,7 +195,9 @@ void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const Symb Value *Val = emitCoercedExpr(Expr, Info); if (!Val) return; std::vector<size_t> Transfers; - bool CopySource = isObjectLValue(Expr); + // Only a value of the same type is an existing object to copy; a + // converted one is already a fresh temporary. + bool CopySource = isObjectLValue(Expr) && ExprType && ExprType->sameType(Info); if (!CopySource) { materializeOperatorReceiver(Val, Info); if (typeNeedsDestruction(Info->Name)) Transfers.push_back(StackObjects.size() - 1); |
