Commit 897e783763
Changed files (11)
doc/langref.html.in
@@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
-PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
+PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
+
+PromiseType = "promise" option("->" TypeExpr)
ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
src/all_types.hpp
@@ -409,6 +409,7 @@ enum NodeType {
NodeTypeResume,
NodeTypeAwaitExpr,
NodeTypeSuspend,
+ NodeTypePromiseType,
};
struct AstNodeRoot {
@@ -879,6 +880,10 @@ struct AstNodeSuspend {
AstNode *promise_symbol;
};
+struct AstNodePromiseType {
+ AstNode *payload_type; // can be NULL
+};
+
struct AstNode {
enum NodeType type;
size_t line;
@@ -939,6 +944,7 @@ struct AstNode {
AstNodeResumeExpr resume_expr;
AstNodeAwaitExpr await_expr;
AstNodeSuspend suspend;
+ AstNodePromiseType promise_type;
} data;
};
@@ -1947,6 +1953,7 @@ enum IrInstructionId {
IrInstructionIdSetRuntimeSafety,
IrInstructionIdSetFloatMode,
IrInstructionIdArrayType,
+ IrInstructionIdPromiseType,
IrInstructionIdSliceType,
IrInstructionIdAsm,
IrInstructionIdSizeOf,
@@ -2365,6 +2372,12 @@ struct IrInstructionArrayType {
IrInstruction *child_type;
};
+struct IrInstructionPromiseType {
+ IrInstruction base;
+
+ IrInstruction *payload_type;
+};
+
struct IrInstructionSliceType {
IrInstruction base;
src/analyze.cpp
@@ -3254,6 +3254,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeResume:
case NodeTypeAwaitExpr:
case NodeTypeSuspend:
+ case NodeTypePromiseType:
zig_unreachable();
}
}
src/ast_render.cpp
@@ -250,6 +250,8 @@ static const char *node_type_str(NodeType node_type) {
return "AwaitExpr";
case NodeTypeSuspend:
return "Suspend";
+ case NodeTypePromiseType:
+ return "PromiseType";
}
zig_unreachable();
}
@@ -781,6 +783,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_ungrouped(ar, node->data.array_type.child_type);
break;
}
+ case NodeTypePromiseType:
+ {
+ fprintf(ar->f, "promise");
+ if (node->data.promise_type.payload_type != nullptr) {
+ fprintf(ar->f, "->");
+ render_node_grouped(ar, node->data.promise_type.payload_type);
+ }
+ break;
+ }
case NodeTypeErrorType:
fprintf(ar->f, "error");
break;
src/codegen.cpp
@@ -4205,6 +4205,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdSetRuntimeSafety:
case IrInstructionIdSetFloatMode:
case IrInstructionIdArrayType:
+ case IrInstructionIdPromiseType:
case IrInstructionIdSliceType:
case IrInstructionIdSizeOf:
case IrInstructionIdSwitchTarget:
src/ir.cpp
@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
return IrInstructionIdArrayType;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
+ return IrInstructionIdPromiseType;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
return IrInstructionIdSliceType;
}
@@ -1469,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
+static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *payload_type)
+{
+ IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);
+ instruction->payload_type = payload_type;
+
+ if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
{
@@ -5074,6 +5089,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
}
}
+static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {
+ assert(node->type == NodeTypePromiseType);
+
+ AstNode *payload_type_node = node->data.promise_type.payload_type;
+ IrInstruction *payload_type_value = nullptr;
+
+ if (payload_type_node != nullptr) {
+ payload_type_value = ir_gen_node(irb, payload_type_node, scope);
+ if (payload_type_value == irb->codegen->invalid_instruction)
+ return payload_type_value;
+
+ }
+
+ return ir_build_promise_type(irb, scope, node, payload_type_value);
+}
+
static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeUndefinedLiteral);
return ir_build_const_undefined(irb, scope, node);
@@ -6282,6 +6313,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
case NodeTypeArrayType:
return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
+ case NodeTypePromiseType:
+ return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval);
case NodeTypeStringLiteral:
return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
case NodeTypeUndefinedLiteral:
@@ -14069,6 +14102,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
zig_unreachable();
}
+static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) {
+ TypeTableEntry *promise_type;
+
+ if (instruction->payload_type == nullptr) {
+ promise_type = ira->codegen->builtin_types.entry_promise;
+ } else {
+ TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload_type->other);
+ if (type_is_invalid(payload_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ promise_type = get_promise_type(ira->codegen, payload_type);
+ }
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = promise_type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
IrInstructionSizeOf *size_of_instruction)
{
@@ -17907,6 +17958,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
case IrInstructionIdArrayType:
return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
+ case IrInstructionIdPromiseType:
+ return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
case IrInstructionIdSizeOf:
return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
case IrInstructionIdTestNonNull:
@@ -18232,6 +18285,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdStructFieldPtr:
case IrInstructionIdUnionFieldPtr:
case IrInstructionIdArrayType:
+ case IrInstructionIdPromiseType:
case IrInstructionIdSliceType:
case IrInstructionIdSizeOf:
case IrInstructionIdTestNonNull:
src/ir_print.cpp
@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
ir_print_other_instruction(irp, instruction->child_type);
}
+static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) {
+ fprintf(irp->f, "promise");
+ if (instruction->payload_type != nullptr) {
+ fprintf(irp->f, "->");
+ ir_print_other_instruction(irp, instruction->payload_type);
+ }
+}
+
static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
const char *const_kw = instruction->is_const ? "const " : "";
fprintf(irp->f, "[]%s", const_kw);
@@ -1263,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdArrayType:
ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
break;
+ case IrInstructionIdPromiseType:
+ ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
+ break;
case IrInstructionIdSliceType:
ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
break;
src/parser.cpp
@@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
}
/*
-PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
+PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
*/
@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);
*token_index += 1;
return node;
+ } else if (token->id == TokenIdKeywordPromise) {
+ AstNode *node = ast_create_node(pc, NodeTypePromiseType, token);
+ *token_index += 1;
+ Token *arrow_tok = &pc->tokens->at(*token_index);
+ if (arrow_tok->id == TokenIdArrow) {
+ *token_index += 1;
+ node->data.promise_type.payload_type = ast_parse_type_expr(pc, token_index, true);
+ }
+ return node;
} else if (token->id == TokenIdKeywordError) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdLBrace) {
@@ -3081,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.array_type.child_type, visit, context);
visit_field(&node->data.array_type.align_expr, visit, context);
break;
+ case NodeTypePromiseType:
+ visit_field(&node->data.promise_type.payload_type, visit, context);
+ break;
case NodeTypeErrorType:
// none
break;
src/tokenizer.cpp
@@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"null", TokenIdKeywordNull},
{"or", TokenIdKeywordOr},
{"packed", TokenIdKeywordPacked},
+ {"promise", TokenIdKeywordPromise},
{"pub", TokenIdKeywordPub},
{"resume", TokenIdKeywordResume},
{"return", TokenIdKeywordReturn},
@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordNull: return "null";
case TokenIdKeywordOr: return "or";
case TokenIdKeywordPacked: return "packed";
+ case TokenIdKeywordPromise: return "promise";
case TokenIdKeywordPub: return "pub";
case TokenIdKeywordReturn: return "return";
case TokenIdKeywordSection: return "section";
src/tokenizer.hpp
@@ -76,6 +76,7 @@ enum TokenId {
TokenIdKeywordNull,
TokenIdKeywordOr,
TokenIdKeywordPacked,
+ TokenIdKeywordPromise,
TokenIdKeywordPub,
TokenIdKeywordResume,
TokenIdKeywordReturn,
test/cases/coroutines.zig
@@ -5,6 +5,7 @@ var x: i32 = 1;
test "create a coroutine and cancel it" {
const p = try async<std.debug.global_allocator> simpleAsyncFn();
+ comptime assert(@typeOf(p) == promise->void);
cancel p;
assert(x == 2);
}