Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Codex.Codex/Emit/CSharpEmitterExpressions.codex
Original file line number Diff line number Diff line change
Expand Up @@ -637,9 +637,12 @@ Section: Expression Emission

emit-do : List IRDoStmt -> CodexType -> List ArityEntry -> Text
emit-do (stmts) (ty) (arities) =
let ret-type = cs-type ty
let actual-ty = when ty
if EffectfulTy (effs) (ret) -> ret
if _ -> ty
in let ret-type = cs-type actual-ty
in let len = list-length stmts
in when ty
in when actual-ty
if VoidTy -> "((Func<object>)(() => { " ++ emit-do-stmts stmts 0 len False arities ++ " return null; }))()"
if NothingTy -> "((Func<object>)(() => { " ++ emit-do-stmts stmts 0 len False arities ++ " return null; }))()"
if ErrorTy -> "((Func<object>)(() => { " ++ emit-do-stmts stmts 0 len False arities ++ " return null; }))()"
Expand Down
11 changes: 9 additions & 2 deletions Codex.Codex/Emit/X86_64.codex
Original file line number Diff line number Diff line change
Expand Up @@ -1368,8 +1368,11 @@ Section: Builtin Emission
if _ -> 0
in let val-result = emit-expr st1 (list-at args 2)
in let loaded = load-local (val-result.state) (rec-loc.reg)
in let st-checked = when rec-ty
if RecordTy (rn) (rf) -> loaded.state
if _ -> st-add-error (loaded.state) cdx-ir-error ("record-set: unresolved type for field '" ++ field-name ++ "'") (ir-expr-span (list-at args 0))
in EmitResult {
state = st-append-text (loaded.state) (mov-store (loaded.reg) (val-result.reg) (field-idx * 8)),
state = st-append-text st-checked (mov-store (loaded.reg) (val-result.reg) (field-idx * 8)),
reg = loaded.reg
}

Expand Down Expand Up @@ -1863,6 +1866,7 @@ Section: Record Emission
let raw = lookup-type-binding (st.type-defs) (cname.value)
in resolve-constructed-raw raw ty
if EffectfulTy (effs) (ret) -> resolve-constructed-ty st ret
if ForAllTy (id) (body) -> resolve-constructed-ty st body
if _ -> ty

strip-fun-args-emitter : CodexType -> CodexType
Expand Down Expand Up @@ -1954,7 +1958,10 @@ Section: Record Emission
if RecordTy (rname) (rfields) -> find-record-field-index rfields field-name 0
if _ -> 0
in let rec-result = emit-expr st rec-expr
in let rd = alloc-temp (rec-result.state)
in let st-checked = when rec-ty
if RecordTy (rn) (rf) -> rec-result.state
if _ -> st-add-error (rec-result.state) cdx-ir-error ("emit-field-access: unresolved type for field '" ++ field-name ++ "'") (ir-expr-span rec-expr)
in let rd = alloc-temp st-checked
in EmitResult {
state = st-append-text (rd.state) (mov-load (rd.reg) (rec-result.reg) (field-idx * 8)),
reg = rd.reg
Expand Down
26 changes: 20 additions & 6 deletions Codex.Codex/IR/Lowering.codex
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ Section: Expression Lowering
if AFieldAccess (rec) (field) (s) ->
let rec-ir = lower-expr rec ErrorTy ctx
in let rec-ty = deep-resolve (ctx.ust) (ir-expr-type rec-ir)
in let resolved-rec-ty = when rec-ty
if RecordTy (rn) (rf) -> rec-ty
in let stripped-rec-ty = when rec-ty
if EffectfulTy (effs) (ret) -> deep-resolve (ctx.ust) ret
if ForAllTy (id) (body) -> deep-resolve (ctx.ust) body
if _ -> rec-ty
in let resolved-rec-ty = when stripped-rec-ty
if RecordTy (rn) (rf) -> stripped-rec-ty
if ConstructedTy (cname) (cargs) ->
let ctor-raw = lookup-type (ctx.types) (cname.value)
in let resolved-record = when ctor-raw
if ErrorTy -> rec-ty
if ErrorTy -> stripped-rec-ty
if _ -> strip-fun-args-lower (deep-resolve (ctx.ust) ctor-raw)
in when resolved-record
if RecordTy (rn) (rf) -> resolved-record
if _ -> rec-ty
if _ -> rec-ty
if _ -> stripped-rec-ty
if _ -> stripped-rec-ty
in let field-ty = when resolved-rec-ty
if RecordTy (rname) (rfields) -> lookup-record-field rfields (field.value)
if _ -> ty
Expand Down Expand Up @@ -329,7 +333,17 @@ Section: Collections and Do

lower-do : List ADoStmt -> CodexType -> LowerCtx -> SourceSpan -> IRExpr
lower-do (stmts) (ty) (ctx) (sp) =
IrDo (lower-do-stmts-loop stmts ty ctx 0 (list-length stmts)) ty sp
let lowered = lower-do-stmts-loop stmts ty ctx 0 (list-length stmts)
in let do-ty = do-block-type lowered ty
in IrDo lowered do-ty sp

do-block-type : List IRDoStmt -> CodexType -> CodexType
do-block-type (stmts) (fallback) =
if list-length stmts == 0 then fallback
else let last = list-at stmts (list-length stmts - 1)
in when last
if IrDoExec (e) (sp) -> ir-expr-type e
if IrDoBind (nm) (bty) (e) (sp) -> bty

lower-do-stmts-loop : List ADoStmt -> CodexType -> LowerCtx -> Integer -> Integer -> List IRDoStmt
lower-do-stmts-loop (stmts) (ty) (ctx) (i) (len) =
Expand Down
6 changes: 6 additions & 0 deletions Codex.Codex/Syntax/ParserCore.codex
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ Section: TokenKind Predicates
if InKeyword -> True
if _ -> False

is-else-keyword : TokenKind -> Boolean
is-else-keyword (k) =
when k
if ElseKeyword -> True
if _ -> False

is-minus : TokenKind -> Boolean
is-minus (k) =
when k
Expand Down
2 changes: 2 additions & 0 deletions Codex.Codex/Syntax/ParserExpressions.codex
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ Section: Compound Expression Parsing
parse-do-stmts (acc) (st) =
if is-done st then ExprOk (DoExpr acc) st
else if is-dedent (current-kind st) then ExprOk (DoExpr acc) st
else if is-else-keyword (current-kind st) then ExprOk (DoExpr acc) st
else if is-in-keyword (current-kind st) then ExprOk (DoExpr acc) st
else if looks-like-top-level-def st then ExprOk (DoExpr acc) st
else if is-chapter-header st then ExprOk (DoExpr acc) st
else if is-section-header st then ExprOk (DoExpr acc) st
Expand Down
1 change: 1 addition & 0 deletions Codex.Codex/Types/Unifier.codex
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ Section: Deep Resolve
if LinkedListTy (elem) -> LinkedListTy (deep-resolve st elem)
if ConstructedTy (name) (args) -> ConstructedTy name (deep-resolve-list st args 0 (list-length args) [])
if ForAllTy (id) (body) -> ForAllTy id (deep-resolve st body)
if EffectfulTy (effs) (ret) -> EffectfulTy effs (deep-resolve st ret)
if SumTy (name) (ctors) -> resolved
if RecordTy (name) (fields) -> resolved
if _ -> resolved
Expand Down
44 changes: 38 additions & 6 deletions src/Codex.Emit.X86_64/X86_64CodeGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,8 +1391,13 @@ byte EmitRecord(IRRecord rec)
fieldMap[name] = saved;
}

RecordType? rt = rec.Type as RecordType;
if (rt is null && rec.Type is ConstructedType ctRec)
CodexType recCreateType = rec.Type;
if (recCreateType is EffectfulType eftRc)
recCreateType = eftRc.Return;
if (recCreateType is ForAllType fatRc)
recCreateType = fatRc.Body;
RecordType? rt = recCreateType as RecordType;
if (rt is null && recCreateType is ConstructedType ctRec)
rt = m_typeDefs[ctRec.Constructor.Value] as RecordType;

int fieldCount = rt?.Fields.Length ?? rec.Fields.Length;
Expand Down Expand Up @@ -1428,8 +1433,14 @@ byte EmitFieldAccess(IRFieldAccess fa)
byte baseReg = EmitExpr(fa.Record);
int fieldIndex = 0;

RecordType? rt = fa.Record.Type as RecordType;
if (rt is null && fa.Record.Type is ConstructedType ctFa)
CodexType recType = fa.Record.Type;
if (recType is EffectfulType eft)
recType = eft.Return;
if (recType is ForAllType fat)
recType = fat.Body;

RecordType? rt = recType as RecordType;
if (rt is null && recType is ConstructedType ctFa)
rt = m_typeDefs[ctFa.Constructor.Value] as RecordType;

if (rt is not null)
Expand All @@ -1443,6 +1454,12 @@ byte EmitFieldAccess(IRFieldAccess fa)
}
}
}
else
{
Console.Error.WriteLine($"X86_64: EmitFieldAccess: unresolved record type for field '{fa.FieldName}' — " +
$"original type = {fa.Record.Type} ({fa.Record.Type.GetType().Name}), " +
$"unwrapped type = {recType} ({recType.GetType().Name})");
}

byte rd = AllocTemp();
X86_64Encoder.MovLoad(m_text, rd, baseReg, fieldIndex * 8);
Expand Down Expand Up @@ -1842,8 +1859,13 @@ byte TryEmitBuiltin(string name, List<IRExpr> args)
StoreLocal(recLocal, recReg);

string fieldName = args[1] is IRTextLit lit ? lit.Value : "";
RecordType? rt = args[0].Type as RecordType;
if (rt is null && args[0].Type is ConstructedType ctRs)
CodexType rsType = args[0].Type;
if (rsType is EffectfulType eftRs)
rsType = eftRs.Return;
if (rsType is ForAllType fatRs)
rsType = fatRs.Body;
RecordType? rt = rsType as RecordType;
if (rt is null && rsType is ConstructedType ctRs)
rt = m_typeDefs[ctRs.Constructor.Value] as RecordType;

int fieldIndex = 0;
Expand All @@ -1858,6 +1880,12 @@ byte TryEmitBuiltin(string name, List<IRExpr> args)
}
}
}
else
{
Console.Error.WriteLine($"X86_64: record-set: unresolved record type for field '{fieldName}' — " +
$"original type = {args[0].Type} ({args[0].Type.GetType().Name}), " +
$"unwrapped type = {rsType} ({rsType.GetType().Name})");
}

byte valReg = EmitExpr(args[2]);
byte ptrReg = LoadLocal(recLocal);
Expand Down Expand Up @@ -5152,6 +5180,10 @@ void EmitListAppendHelper()

CodexType ResolveType(CodexType type)
{
if (type is EffectfulType eft)
return ResolveType(eft.Return);
if (type is ForAllType fat)
return ResolveType(fat.Body);
if (type is ConstructedType ct && m_typeDefs[ct.Constructor.Value] is CodexType resolved)
return resolved;
if (type is ListType lt)
Expand Down
17 changes: 16 additions & 1 deletion src/Codex.IR/Lowering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,22 @@ IRExpr LowerDoExpr(DoExpr doExpr, CodexType expectedType)
}

m_localEnv = savedEnv;
return new IRDo(statements.ToImmutable(), expectedType);

// Compute the do-block's type from the last statement rather than
// relying on expectedType, which is often ErrorType when the do
// appears in let-binding RHS. This matches InferDoExpr's logic.
ImmutableArray<IRDoStatement> stmts = statements.ToImmutable();
CodexType doType = expectedType;
if (stmts.Length > 0)
{
IRDoStatement last = stmts[^1];
if (last is IRDoExec exec)
doType = exec.Expression.Type;
else if (last is IRDoBind bind)
doType = bind.NameType;
}

return new IRDo(stmts, doType);
}

IRExpr LowerHandleExpr(HandleExpr handleExpr, CodexType expectedType)
Expand Down
3 changes: 2 additions & 1 deletion src/Codex.Syntax/Parser.Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,8 @@ ExpressionNode ParseDoExpression()

List<DoStatementNode> statements = [];
while (!IsAtEnd
&& Current.Kind is not (TokenKind.EndOfFile or TokenKind.Dedent)
&& Current.Kind is not (TokenKind.EndOfFile or TokenKind.Dedent
or TokenKind.ElseKeyword or TokenKind.InKeyword)
&& !(Current.Kind == TokenKind.Identifier && Peek(1)?.Kind == TokenKind.Colon))
{
if (Current.Kind == TokenKind.Identifier && Peek(1)?.Kind == TokenKind.LeftArrow)
Expand Down
Loading