mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Function referencing in @return? for simplified fault declarations. Check @return? eagerly #2340.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
- Missing imports allowed if module `@if` evaluates to false #2251.
|
- Missing imports allowed if module `@if` evaluates to false #2251.
|
||||||
- Add default exception handler to Win32 #2557.
|
- Add default exception handler to Win32 #2557.
|
||||||
- Accept `"$schema"` as key in `project.json` #2554.
|
- Accept `"$schema"` as key in `project.json` #2554.
|
||||||
|
- Function referencing in `@return?` for simplified fault declarations. Check `@return?` eagerly #2340.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable.
|
- `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable.
|
||||||
|
|||||||
@@ -600,6 +600,12 @@ typedef struct
|
|||||||
};
|
};
|
||||||
} FuncDecl;
|
} FuncDecl;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Signature signature;
|
||||||
|
AstId docs;
|
||||||
|
} FnTypeDecl;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -740,7 +746,7 @@ typedef struct Decl_
|
|||||||
EnumConstantDecl enum_constant;
|
EnumConstantDecl enum_constant;
|
||||||
ExecDecl exec_decl;
|
ExecDecl exec_decl;
|
||||||
Expr* expand_decl;
|
Expr* expand_decl;
|
||||||
Signature fntype_decl;
|
FnTypeDecl fntype_decl;
|
||||||
FuncDecl func_decl;
|
FuncDecl func_decl;
|
||||||
ImportDecl import;
|
ImportDecl import;
|
||||||
IncludeDecl include;
|
IncludeDecl include;
|
||||||
@@ -1527,6 +1533,7 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool resolved;
|
bool resolved;
|
||||||
|
bool expanding;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
Expr *expr;
|
Expr *expr;
|
||||||
@@ -2296,6 +2303,7 @@ bool may_cast(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit,
|
|||||||
|
|
||||||
void cast_no_check(Expr *expr, Type *to_type, bool add_optional);
|
void cast_no_check(Expr *expr, Type *to_type, bool add_optional);
|
||||||
|
|
||||||
|
|
||||||
bool cast_to_index_len(SemaContext *context, Expr *index, bool is_len);
|
bool cast_to_index_len(SemaContext *context, Expr *index, bool is_len);
|
||||||
|
|
||||||
const char *llvm_codegen(void *context);
|
const char *llvm_codegen(void *context);
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ RETRY:
|
|||||||
case AST_CONTRACT_FAULT:
|
case AST_CONTRACT_FAULT:
|
||||||
if (ast->contract_fault.resolved)
|
if (ast->contract_fault.resolved)
|
||||||
{
|
{
|
||||||
MACRO_COPY_DECL(ast->contract_fault.decl);
|
fixup_decl(c, &ast->contract_fault.decl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1097,7 +1097,8 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
|||||||
MACRO_COPY_DECL_LIST(copy->enums.values);
|
MACRO_COPY_DECL_LIST(copy->enums.values);
|
||||||
break;
|
break;
|
||||||
case DECL_FNTYPE:
|
case DECL_FNTYPE:
|
||||||
copy_signature_deep(c, ©->fntype_decl);
|
copy_signature_deep(c, ©->fntype_decl.signature);
|
||||||
|
MACRO_COPY_ASTID(copy->fntype_decl.docs);
|
||||||
break;
|
break;
|
||||||
case DECL_FUNC:
|
case DECL_FUNC:
|
||||||
copy_decl_type(copy);
|
copy_decl_type(copy);
|
||||||
|
|||||||
@@ -2181,13 +2181,15 @@ static inline void decl_add_type(Decl *decl, TypeKind kind)
|
|||||||
type->decl = decl;
|
type->decl = decl;
|
||||||
decl->type = type;
|
decl->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* typedef_declaration ::= ALIAS TYPE_IDENT attributes? '=' typedef_type ';'
|
* typedef_declaration ::= ALIAS TYPE_IDENT attributes? '=' typedef_type ';'
|
||||||
*
|
*
|
||||||
* typedef_type ::= func_typedef | type generic_params?
|
* typedef_type ::= func_typedef | type generic_params?
|
||||||
* func_typedef ::= 'fn' optional_type parameter_type_list
|
* func_typedef ::= 'fn' optional_type parameter_type_list
|
||||||
*/
|
*/
|
||||||
static inline Decl *parse_alias_type(ParseContext *c)
|
static inline Decl *parse_alias_type(ParseContext *c, AstId contracts, bool has_real_contracts)
|
||||||
{
|
{
|
||||||
advance_and_verify(c, TOKEN_ALIAS);
|
advance_and_verify(c, TOKEN_ALIAS);
|
||||||
|
|
||||||
@@ -2198,7 +2200,7 @@ static inline Decl *parse_alias_type(ParseContext *c)
|
|||||||
if (token_is_any_type(c->tok))
|
if (token_is_any_type(c->tok))
|
||||||
{
|
{
|
||||||
PRINT_ERROR_HERE("'%s' is the name of a built-in type and can't be used as an alias.",
|
PRINT_ERROR_HERE("'%s' is the name of a built-in type and can't be used as an alias.",
|
||||||
token_type_to_string(c->tok));
|
token_type_to_string(c->tok));
|
||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
}
|
}
|
||||||
if (token_is_some_ident(c->tok))
|
if (token_is_some_ident(c->tok))
|
||||||
@@ -2223,8 +2225,9 @@ static inline Decl *parse_alias_type(ParseContext *c)
|
|||||||
Decl *decl_type = decl_new(DECL_FNTYPE, decl->name, c->prev_span);
|
Decl *decl_type = decl_new(DECL_FNTYPE, decl->name, c->prev_span);
|
||||||
decl->type_alias_decl.decl = decl_type;
|
decl->type_alias_decl.decl = decl_type;
|
||||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
|
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
|
||||||
decl_type->fntype_decl.rtype = type_infoid(type_info);
|
decl_type->fntype_decl.signature.rtype = type_infoid(type_info);
|
||||||
if (!parse_fn_parameter_list(c, &(decl_type->fntype_decl)))
|
decl_type->fntype_decl.docs = contracts;
|
||||||
|
if (!parse_fn_parameter_list(c, &(decl_type->fntype_decl.signature)))
|
||||||
{
|
{
|
||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
}
|
}
|
||||||
@@ -2235,6 +2238,11 @@ static inline Decl *parse_alias_type(ParseContext *c)
|
|||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_real_contracts)
|
||||||
|
{
|
||||||
|
RETURN_PRINT_ERROR_AT(poisoned_decl, astptr(contracts), "Contracts are only used for modules, functions and macros.");
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Now parse the type which we know is here.
|
// 2. Now parse the type which we know is here.
|
||||||
|
|
||||||
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_decl);
|
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_decl);
|
||||||
@@ -2413,13 +2421,17 @@ static inline Decl *parse_attrdef(ParseContext *c)
|
|||||||
/**
|
/**
|
||||||
* define_decl ::= ALIAS define_type_body
|
* define_decl ::= ALIAS define_type_body
|
||||||
*/
|
*/
|
||||||
static inline Decl *parse_alias(ParseContext *c)
|
static inline Decl *parse_alias(ParseContext *c, AstId contracts, bool has_real_contracts)
|
||||||
{
|
{
|
||||||
switch (peek(c))
|
switch (peek(c))
|
||||||
{
|
{
|
||||||
case TOKEN_TYPE_IDENT:
|
case TOKEN_TYPE_IDENT:
|
||||||
return parse_alias_type(c);
|
return parse_alias_type(c, contracts, has_real_contracts);
|
||||||
default:
|
default:
|
||||||
|
if (has_real_contracts)
|
||||||
|
{
|
||||||
|
RETURN_PRINT_ERROR_AT(poisoned_decl, astptr(contracts), "Contracts are only used for modules, functions and macros.");
|
||||||
|
}
|
||||||
return parse_alias_ident(c);
|
return parse_alias_ident(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3335,8 +3347,7 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
|||||||
PRINT_ERROR_HERE("There are more than one doc comment in a row, that is not allowed.");
|
PRINT_ERROR_HERE("There are more than one doc comment in a row, that is not allowed.");
|
||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
case TOKEN_ALIAS:
|
case TOKEN_ALIAS:
|
||||||
if (has_real_contracts) goto CONTRACT_NOT_ALLOWED;
|
decl = parse_alias(c, contracts, has_real_contracts);
|
||||||
decl = parse_alias(c);
|
|
||||||
if (decl->decl_kind == DECL_ALIAS_PATH)
|
if (decl->decl_kind == DECL_ALIAS_PATH)
|
||||||
{
|
{
|
||||||
if (!context_out)
|
if (!context_out)
|
||||||
|
|||||||
@@ -1492,8 +1492,12 @@ static inline bool sema_analyse_fntype(SemaContext *context, Decl *decl, bool *e
|
|||||||
{
|
{
|
||||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FNTYPE, erase_decl)) return decl_poison(decl);
|
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FNTYPE, erase_decl)) return decl_poison(decl);
|
||||||
if (*erase_decl) return true;
|
if (*erase_decl) return true;
|
||||||
Signature *sig = &decl->fntype_decl;
|
Signature *sig = &decl->fntype_decl.signature;
|
||||||
return sema_analyse_function_signature(context, decl, NULL, sig->abi, sig);
|
if (!sema_analyse_function_signature(context, decl, NULL, sig->abi, sig)) return false;
|
||||||
|
bool pure = false;
|
||||||
|
if (!sema_analyse_doc_header(context, decl->fntype_decl.docs, sig->params, NULL, &pure)) return false;
|
||||||
|
sig->attrs.is_pure = pure;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sema_analyse_type_alias(SemaContext *context, Decl *decl, bool *erase_decl)
|
static inline bool sema_analyse_type_alias(SemaContext *context, Decl *decl, bool *erase_decl)
|
||||||
@@ -1507,7 +1511,7 @@ static inline bool sema_analyse_type_alias(SemaContext *context, Decl *decl, boo
|
|||||||
Decl *fn_decl = decl->type_alias_decl.decl;
|
Decl *fn_decl = decl->type_alias_decl.decl;
|
||||||
fn_decl->is_export = is_export;
|
fn_decl->is_export = is_export;
|
||||||
fn_decl->unit = decl->unit;
|
fn_decl->unit = decl->unit;
|
||||||
fn_decl->type = type_new_func(fn_decl, &fn_decl->fntype_decl);
|
fn_decl->type = type_new_func(fn_decl, &fn_decl->fntype_decl.signature);
|
||||||
decl->type->canonical = type_get_func_ptr(fn_decl->type);
|
decl->type->canonical = type_get_func_ptr(fn_decl->type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3035,7 +3039,7 @@ INLINE bool update_abi(Decl *decl, CallABI abi)
|
|||||||
{
|
{
|
||||||
if (decl->decl_kind == DECL_FNTYPE)
|
if (decl->decl_kind == DECL_FNTYPE)
|
||||||
{
|
{
|
||||||
decl->fntype_decl.abi = abi;
|
decl->fntype_decl.signature.abi = abi;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
decl->func_decl.signature.abi = abi;
|
decl->func_decl.signature.abi = abi;
|
||||||
@@ -3403,8 +3407,8 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
|
|||||||
decl->func_decl.signature.attrs.format = val + 1;
|
decl->func_decl.signature.attrs.format = val + 1;
|
||||||
return true;
|
return true;
|
||||||
case DECL_FNTYPE:
|
case DECL_FNTYPE:
|
||||||
if (decl->fntype_decl.attrs.format) break;
|
if (decl->fntype_decl.signature.attrs.format) break;
|
||||||
decl->fntype_decl.attrs.format = val + 1;
|
decl->fntype_decl.signature.attrs.format = val + 1;
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -3764,8 +3768,72 @@ bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **attrs, Att
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive)
|
||||||
|
{
|
||||||
|
FOREACH(Ast *, ret, directive->contract_stmt.faults)
|
||||||
|
{
|
||||||
|
if (ret->contract_fault.expanding) continue;
|
||||||
|
if (ret->contract_fault.resolved)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Expr *expr = ret->contract_fault.expr;
|
||||||
|
if (expr->expr_kind == EXPR_RETHROW)
|
||||||
|
{
|
||||||
|
Expr *inner = expr->rethrow_expr.inner;
|
||||||
|
if (!sema_analyse_expr(context, inner)) return false;
|
||||||
|
Decl *decl;
|
||||||
|
switch (inner->expr_kind)
|
||||||
|
{
|
||||||
|
case EXPR_IDENTIFIER:
|
||||||
|
decl = inner->ident_expr;
|
||||||
|
break;
|
||||||
|
case EXPR_TYPEINFO:
|
||||||
|
{
|
||||||
|
Type *type = inner->type_expr->type;
|
||||||
|
if (type->type_kind != TYPE_ALIAS) goto IS_FAULT;
|
||||||
|
decl = type->decl;
|
||||||
|
ASSERT(decl->decl_kind == DECL_TYPE_ALIAS);
|
||||||
|
if (!decl->type_alias_decl.is_func) goto IS_FAULT;
|
||||||
|
decl = decl->type_alias_decl.decl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto IS_FAULT;;
|
||||||
|
}
|
||||||
|
decl = decl_flatten(decl);
|
||||||
|
if (decl->decl_kind != DECL_FNTYPE && decl->decl_kind != DECL_FUNC) goto IS_FAULT;
|
||||||
|
if (!sema_analyse_decl(context, decl)) return false;
|
||||||
|
AstId docs = decl->decl_kind == DECL_FNTYPE ? decl->fntype_decl.docs : decl->func_decl.docs;
|
||||||
|
while (docs)
|
||||||
|
{
|
||||||
|
Ast *doc = astptr(docs);
|
||||||
|
docs = doc->next;
|
||||||
|
if (doc->contract_stmt.kind != CONTRACT_OPTIONALS) continue;
|
||||||
|
ret->contract_fault.expanding = true;
|
||||||
|
bool success = sema_analyse_optional_returns(context, doc);
|
||||||
|
ret->contract_fault.expanding = false;
|
||||||
|
if (!success) false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IS_FAULT:;
|
||||||
|
if (!sema_analyse_expr_rvalue(context, expr)) return false;
|
||||||
|
if (expr->type->canonical != type_fault)
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(expr, "Expected a fault here.");
|
||||||
|
}
|
||||||
|
if (!expr_is_const_fault(expr)) RETURN_SEMA_ERROR(expr, "A constant fault is required.");
|
||||||
|
Decl *decl = expr->const_expr.fault;
|
||||||
|
if (!decl) RETURN_SEMA_ERROR(expr, "A non-null fault is required.");
|
||||||
|
ret->contract_fault.decl = decl;
|
||||||
|
ret->contract_fault.resolved = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool sema_analyse_doc_header(SemaContext *context, AstId doc,
|
static inline bool sema_analyse_doc_header(SemaContext *context, AstId doc,
|
||||||
Decl **params, Decl **extra_params, bool *pure_ref)
|
Decl **params, Decl **extra_params, bool *pure_ref)
|
||||||
{
|
{
|
||||||
while (doc)
|
while (doc)
|
||||||
{
|
{
|
||||||
@@ -3782,6 +3850,10 @@ static inline bool sema_analyse_doc_header(SemaContext *context, AstId doc,
|
|||||||
*pure_ref = true;
|
*pure_ref = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (directive_kind == CONTRACT_OPTIONALS)
|
||||||
|
{
|
||||||
|
if (!sema_analyse_optional_returns(context, directive)) return false;
|
||||||
|
}
|
||||||
if (directive_kind != CONTRACT_PARAM) continue;
|
if (directive_kind != CONTRACT_PARAM) continue;
|
||||||
const char *param_name = directive->contract_stmt.param.name;
|
const char *param_name = directive->contract_stmt.param.name;
|
||||||
Decl *param = NULL;
|
Decl *param = NULL;
|
||||||
@@ -4258,6 +4330,7 @@ CHECK_DONE:
|
|||||||
"'extern' or place it in an .c3i file.");
|
"'extern' or place it in an .c3i file.");
|
||||||
}
|
}
|
||||||
bool pure = false;
|
bool pure = false;
|
||||||
|
|
||||||
if (!sema_analyse_doc_header(context, decl->func_decl.docs, decl->func_decl.signature.params, NULL,
|
if (!sema_analyse_doc_header(context, decl->func_decl.docs, decl->func_decl.signature.params, NULL,
|
||||||
&pure)) return false;
|
&pure)) return false;
|
||||||
decl->func_decl.signature.attrs.is_pure = pure;
|
decl->func_decl.signature.attrs.is_pure = pure;
|
||||||
|
|||||||
@@ -2463,7 +2463,16 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Decl
|
|||||||
*any_val = *(any_val->inner_expr);
|
*any_val = *(any_val->inner_expr);
|
||||||
}
|
}
|
||||||
expr->call_expr.function_contracts = 0;
|
expr->call_expr.function_contracts = 0;
|
||||||
AstId docs = decl->func_decl.docs;
|
AstId docs;
|
||||||
|
if (decl->decl_kind == DECL_FNTYPE)
|
||||||
|
{
|
||||||
|
docs = decl->fntype_decl.docs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
docs = decl->func_decl.docs;
|
||||||
|
}
|
||||||
|
|
||||||
if (!safe_mode_enabled() || !sema_has_require(docs)) goto SKIP_CONTRACTS;
|
if (!safe_mode_enabled() || !sema_has_require(docs)) goto SKIP_CONTRACTS;
|
||||||
SemaContext temp_context;
|
SemaContext temp_context;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|||||||
@@ -636,7 +636,7 @@ RETRY:
|
|||||||
case DECL_MACRO:
|
case DECL_MACRO:
|
||||||
UNREACHABLE_VOID
|
UNREACHABLE_VOID
|
||||||
case DECL_FNTYPE:
|
case DECL_FNTYPE:
|
||||||
sema_trace_func_liveness(&decl->fntype_decl);
|
sema_trace_func_liveness(&decl->fntype_decl.signature);
|
||||||
return;
|
return;
|
||||||
case DECL_FUNC:
|
case DECL_FUNC:
|
||||||
sema_trace_func_liveness(&decl->func_decl.signature);
|
sema_trace_func_liveness(&decl->func_decl.signature);
|
||||||
|
|||||||
@@ -494,6 +494,11 @@ static inline bool sema_check_return_matches_opt_returns(SemaContext *context, E
|
|||||||
if (opt == fault) return true;
|
if (opt == fault) return true;
|
||||||
}
|
}
|
||||||
// No match
|
// No match
|
||||||
|
FOREACH(Decl *, opt, context->call_env.opt_returns)
|
||||||
|
{
|
||||||
|
assert(opt->decl_kind == DECL_FAULT);
|
||||||
|
if (opt == fault) return true;
|
||||||
|
}
|
||||||
RETURN_SEMA_ERROR(ret_expr, "This value does not match declared optional returns, it needs to be declared with the other optional returns.");
|
RETURN_SEMA_ERROR(ret_expr, "This value does not match declared optional returns, it needs to be declared with the other optional returns.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3283,14 +3288,59 @@ static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive)
|
|||||||
{
|
{
|
||||||
FOREACH(Ast *, ret, directive->contract_stmt.faults)
|
FOREACH(Ast *, ret, directive->contract_stmt.faults)
|
||||||
{
|
{
|
||||||
if (ret->contract_fault.resolved) continue;
|
if (ret->contract_fault.expanding) continue;
|
||||||
Expr *expr = ret->contract_fault.expr;
|
if (ret->contract_fault.resolved)
|
||||||
if (expr->expr_kind != EXPR_UNRESOLVED_IDENTIFIER && !expr->unresolved_ident_expr.is_const)
|
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(expr, "Expected a fault name here.");
|
vec_add(context->call_env.opt_returns, ret->contract_fault.decl);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
Expr *expr = ret->contract_fault.expr;
|
||||||
|
if (expr->expr_kind == EXPR_RETHROW)
|
||||||
|
{
|
||||||
|
Expr *inner = expr->rethrow_expr.inner;
|
||||||
|
if (!sema_analyse_expr(context, inner)) return false;
|
||||||
|
Decl *decl;
|
||||||
|
switch (inner->expr_kind)
|
||||||
|
{
|
||||||
|
case EXPR_IDENTIFIER:
|
||||||
|
decl = inner->ident_expr;
|
||||||
|
break;
|
||||||
|
case EXPR_TYPEINFO:
|
||||||
|
{
|
||||||
|
Type *type = inner->type_expr->type;
|
||||||
|
if (type->type_kind != TYPE_ALIAS) goto IS_FAULT;
|
||||||
|
decl = type->decl;
|
||||||
|
ASSERT(decl->decl_kind == DECL_TYPE_ALIAS);
|
||||||
|
if (!decl->type_alias_decl.is_func) goto IS_FAULT;
|
||||||
|
decl = decl->type_alias_decl.decl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto IS_FAULT;;
|
||||||
|
}
|
||||||
|
decl = decl_flatten(decl);
|
||||||
|
if (decl->decl_kind != DECL_FNTYPE && decl->decl_kind != DECL_FUNC) goto IS_FAULT;
|
||||||
|
if (!sema_analyse_decl(context, decl)) return false;
|
||||||
|
AstId docs = decl->decl_kind == DECL_FNTYPE ? decl->fntype_decl.docs : decl->func_decl.docs;
|
||||||
|
while (docs)
|
||||||
|
{
|
||||||
|
Ast *doc = astptr(docs);
|
||||||
|
docs = doc->next;
|
||||||
|
if (doc->contract_stmt.kind != CONTRACT_OPTIONALS) continue;
|
||||||
|
ret->contract_fault.expanding = true;
|
||||||
|
bool success = sema_analyse_optional_returns(context, doc);
|
||||||
|
ret->contract_fault.expanding = false;
|
||||||
|
if (!success) false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IS_FAULT:;
|
||||||
if (!sema_analyse_expr_rvalue(context, expr)) return false;
|
if (!sema_analyse_expr_rvalue(context, expr)) return false;
|
||||||
if (!expr_is_const_fault(expr)) RETURN_SEMA_ERROR(expr, "A fault is required.");
|
if (expr->type->canonical != type_fault)
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(expr, "Expected a fault here.");
|
||||||
|
}
|
||||||
|
if (!expr_is_const_fault(expr)) RETURN_SEMA_ERROR(expr, "A constant fault is required.");
|
||||||
Decl *decl = expr->const_expr.fault;
|
Decl *decl = expr->const_expr.fault;
|
||||||
if (!decl) RETURN_SEMA_ERROR(expr, "A non-null fault is required.");
|
if (!decl) RETURN_SEMA_ERROR(expr, "A non-null fault is required.");
|
||||||
ret->contract_fault.decl = decl;
|
ret->contract_fault.decl = decl;
|
||||||
|
|||||||
21
test/test_suite/contracts/contract_copy_optret.c3
Normal file
21
test/test_suite/contracts/contract_copy_optret.c3
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module test;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
<*
|
||||||
|
@return? test!
|
||||||
|
*>
|
||||||
|
fn void? test2()
|
||||||
|
{
|
||||||
|
return NOT_FOUND?;
|
||||||
|
}
|
||||||
|
<*
|
||||||
|
@return? io::EOF, Foo!
|
||||||
|
*>
|
||||||
|
fn void? test()
|
||||||
|
{
|
||||||
|
return NOT_FOUND?;
|
||||||
|
}
|
||||||
|
<*
|
||||||
|
@return? NOT_FOUND
|
||||||
|
*>
|
||||||
|
alias Foo = fn void();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
module contract_err_tests;
|
module contract_err_tests;
|
||||||
|
import std;
|
||||||
<*
|
<*
|
||||||
Hello world
|
Hello world
|
||||||
@param [in] a
|
@param [in] a
|
||||||
|
|||||||
Reference in New Issue
Block a user