Added "guess a number". Fix CT enum / int comparison. Fix some array pointer decay scenarios. Infer type of expression blocks. Correctly merge anyerr.

This commit is contained in:
Christoffer Lerno
2022-02-01 21:41:09 +01:00
committed by Christoffer Lerno
parent ba66aaaf12
commit 06917f2e65
17 changed files with 256 additions and 91 deletions

View File

@@ -0,0 +1,95 @@
module guess_number;
import std::mem;
import std::io;
import libc;
extern fn void printf(char*, ...);
extern fn isize getline(char** linep, usize* linecapp, CFile stream);
struct Game
{
int answer;
bool done;
int guesses;
int high;
}
optnum InputResult
{
NOT_AN_INT,
FAILED_TO_READ,
}
int err_count = 0;
fn int! askGuess(int high)
{
printf("Guess a number between 1 and %d: ", high);
char[] text = readLine()?;
char* end = null;
int value = (int)libc::strtol(text.ptr, &end, 10);
if (end && end[0] >= ' ') return InputResult.NOT_AN_INT!;
return value;
}
fn char[]! readLine()
{
char* chars = mem::talloc(1024)?;
isize loaded = getline(&chars, &&(usize)1023, @libc::stdin());
if (loaded < 0) return InputResult.FAILED_TO_READ!;
chars[loaded] = 0;
return chars[0..(loaded - 1)];
}
fn int! askGuessMulti(int high)
{
while (true)
{
int! result = askGuess(high);
if (catch(result) == InputResult.NOT_AN_INT)
{
printf("I didn't understand that.\n");
err_count++;
continue;
}
return result;
}
$unreachable;
}
fn void! Game.play(Game *game)
{
while (!game.done)
{
int guess = askGuessMulti(game.high)?;
game.report(guess);
game.update(guess);
}
}
fn void Game.report(Game *game, int guess)
{
char[] desc = {|
if (guess < game.answer) return "too low";
if (guess > game.answer) return "too high";
return "the answer";
|};
printf("%d is %.*s.\n", guess, (int)desc.len, desc.ptr);
}
fn void Game.update(Game *game, int guess)
{
if (guess == game.answer) game.done = true;
game.guesses++;
}
fn void! main()
{
libc::srand((int)libc::clock());
int high = 100;
int answer = libc::rand() % high + 1;
Game game = { .answer = answer, .high = high };
game.play();
printf("Finished in %d guesses.\n", game.guesses);
printf("Total input errors: %d.\n", err_count);
}

View File

@@ -4,19 +4,18 @@
module std::io;
import std::mem;
import libc;
import std::env;
struct File
{
void *file;
CFile file;
}
extern fn int _puts(char* message) @extname("puts");
extern fn int printf(char* message, ...);
extern fn int _putchar(char c) @extname("putchar");
extern File *__stdinp;
fn int putchar(char c) @inline
{

View File

@@ -9,6 +9,7 @@ import std::os::macos;
import std::os::windows;
// stdlib
// Constants need to be per os/arch
const int EXIT_FAILURE = 1;
const int EXIT_SUCCESS = 0;
@@ -166,11 +167,11 @@ enum Errno : ErrnoType
fn Errno errno()
{
$if (env::OS_TYPE == OsType.WIN32):
return windows::errno();
return (Errno)windows::errno();
$elif (env::OS_TYPE == OsType.MACOSX):
return macos::errno();
return (Errno)macos::errno();
$elif (env::OS_TYPE == OsType.LINUX):
return linux::errno();
return (Errno)linux::errno();
$else:
return Errno.ENOTRECOVERABLE;
$endif;
@@ -181,10 +182,10 @@ define TerminateFunction = fn void();
define CompareFunction = fn int(void*, void*);
extern fn double atof(char* str);
extern fn int atoi(char* str);
extern fn long atol(char* str);
extern fn CLongLong atoll(char* str);
extern fn double strtod(char* str, char** endptr);
extern fn long strtol(char* str, char** endptr, int base);
extern fn ulong stroul(char* str, char** endptr, int base);
extern fn CLong strtol(char* str, char** endptr, int base);
extern fn CULong stroul(char* str, char** endptr, int base);
extern fn void abort();
extern fn void atexit(TerminateFunction f);
extern fn void exit(int status);
@@ -234,6 +235,28 @@ extern fn void* realloc(void* ptr, usize size);
define Fpos = long;
define CFile = void*;
$switch (env::OS_TYPE):
$case OsType.LINUX:
extern CFile __stdin @extname("stdin");
extern CFile __stdout @extname("stdout");
extern CFile __stderr @extname("stderr");
macro CFile stdin() { return __stdin; }
macro CFile stdout() { return __stdout; }
macro CFile stderr() { return __stderr; }
$case OsType.MACOSX:
extern CFile __stdinp;
extern CFile __stdoutp;
extern CFile __stderrp;
macro CFile stdin() { return __stdinp; }
macro CFile stdout() { return __stdoutp; }
macro CFile stderr() { return __stderrp; }
$case OsType.WIN32:
extern fn CFile __acrt_iob_func(CInt c);
macro CFile stdin() { return __acrt_iob_func(0); }
macro CFile stdout() { return __acrt_iob_func(1); }
macro CFile stderr() { return __acrt_iob_func(2); }
$default:
$endswitch;
// The following needs to be set per arch+os
// For now I have simply pulled the defaults from MacOS

View File

@@ -10,9 +10,9 @@ fn int errno() @inline
return *__errno_location();
}
fn void errno_set(int errno)
fn void errno_set(int err)
{
*(__errno_location()) = errno;
*(__errno_location()) = err;
}
$endif;

View File

@@ -2,14 +2,15 @@ module std::os::macos;
import std::env;
$if (env::OS_TYPE == OsType.MACOSX):
extern fn int* __error();
fn int errno() @inline
{
return *__error();
}
fn void errno_set(int errno)
fn void errno_set(int err)
{
*(__error()) = errno;
*(__error()) = err;
}
$endif;

View File

@@ -2,6 +2,7 @@ module std::os::windows;
import std::env;
$if (env::OS_TYPE == OsType.WIN32):
extern fn int getLastError() @stdcall @extname("GetLastError");
fn int errno() @inline
{

View File

@@ -721,6 +721,23 @@ bool int_is_zero(Int op)
return !op.i.high && !op.i.low;
}
unsigned int_bits_needed(Int op)
{
TypeKind kind = op.type;
Int128 i = op.i;
int bits_used;
if (type_kind_is_signed(kind))
{
if (i128_is_neg(i))
{
i = i128_neg(i);
i = i128_sub64(i, 1);
}
return (unsigned) (1 + 128 - i128_clz(&i));
}
return (unsigned) (128 - i128_clz(&i));
}
Int int_add(Int op1, Int op2)
{
assert(op1.type == op2.type);

View File

@@ -56,6 +56,7 @@ typedef struct TypeInfo_ TypeInfo;
typedef struct Expr_ Expr;
typedef struct Module_ Module;
typedef struct Type_ Type;
typedef Type CanonicalType;
typedef unsigned AstId;
@@ -259,7 +260,7 @@ typedef struct
struct Type_
{
TypeKind type_kind;
Type *canonical;
CanonicalType *canonical;
const char *name;
Type **type_cache;
void *backend_type;
@@ -1428,7 +1429,9 @@ typedef struct
typedef struct SemaContext_
{
// Evaluated in this.
CompilationUnit *unit;
// Compiled in this unit.
CompilationUnit *compilation_unit;
Decl *current_function;
Decl *current_macro;
@@ -1709,6 +1712,7 @@ bool int_comp(Int op1, Int op2, BinaryOp op);
uint64_t int_to_u64(Int op);
int64_t int_to_i64(Int op);
bool int_is_zero(Int op);
unsigned int_bits_needed(Int op);
bool int_fits(Int op1, TypeKind kind);
Int int_rightmost_bits(Int op, unsigned to_bits, TypeKind result_type);
Int int_conv(Int op, TypeKind to_type);
@@ -1851,7 +1855,9 @@ const char *decl_to_name(Decl *decl);
static inline Decl *decl_raw(Decl *decl);
static inline bool decl_ok(Decl *decl) { return !decl || decl->decl_kind != DECL_POISONED; }
static inline bool decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false; }
static inline bool decl_poison(Decl *decl) {
decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false;
}
static inline bool decl_is_struct_type(Decl *decl);
static inline bool decl_is_callable_type(Decl *decl);
static inline bool decl_is_user_defined_type(Decl *decl);
@@ -2112,6 +2118,8 @@ static inline bool type_is_integer_or_bool_kind(Type *type);
static inline bool type_is_numeric(Type *type);
static inline bool type_underlying_is_numeric(Type *type);
static inline bool type_is_pointer(Type *type);
static inline CanonicalType *type_pointer_type(Type *type);
static inline bool type_is_arraylike(Type *type);
static inline bool type_is_promotable_float(Type *type);
static inline bool type_is_promotable_integer(Type *type);
static inline bool type_is_signed(Type *type);
@@ -2128,6 +2136,7 @@ bool type_is_float_or_float_vector(Type *type);
bool type_may_have_sub_elements(Type *type);
static inline bool type_ok(Type *type);
TypeSize type_size(Type *type);
#define type_bit_size(type) (type_size(type) * 8)
const char *type_to_error_string(Type *type);
const char *type_quoted_error_string(Type *type);
@@ -2217,6 +2226,18 @@ static inline bool type_info_poison(TypeInfo *type)
return false;
}
static inline bool type_is_arraylike(Type *type)
{
DECL_TYPE_KIND_REAL(kind, type);
return kind == TYPE_ARRAY || kind == TYPE_VECTOR;
}
static inline CanonicalType *type_pointer_type(Type *type)
{
CanonicalType *res = type->canonical;
if (res->type_kind != TYPE_POINTER) return NULL;
return res->pointer;
}
static inline bool type_is_pointer(Type *type)
{

View File

@@ -123,8 +123,7 @@ bool context_set_module(ParseContext *context, Path *path, TokenId *generic_para
void unit_register_external_symbol(CompilationUnit *unit, Decl *decl)
{
if (decl->decl_kind == DECL_MACRO) return;
assert(decl->external_name && "Missing external name");
if (!decl->module || decl->module == unit->module || !decl->external_name) return;
Decl *prev = stable_get(&unit->external_symbols, decl->external_name);
if (prev) return;
if (decl != stable_set(&unit->external_symbols, decl->external_name, decl))

View File

@@ -76,11 +76,16 @@ static inline bool compare_fps(Real left, Real right, BinaryOp op)
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op)
{
bool is_eq;
switch (left->const_kind)
{
case CONST_BOOL:
return compare_bool(left->b, right->b, op);
case CONST_INTEGER:
if (right->const_kind == CONST_ENUM)
{
return int_comp(left->ixx, right->enum_val->enum_constant.expr->const_expr.ixx, op);
}
return int_comp(left->ixx, right->ixx, op);
case CONST_FLOAT:
return compare_fps(left->fxx.f, right->fxx.f, op);

View File

@@ -2124,7 +2124,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
const char *name_str = TOKSTR(name);
Decl *symbol = module_find_symbol(instantiated_module, name_str);
assert(symbol);
unit_register_external_symbol(c->unit, symbol);
unit_register_external_symbol(c->compilation_unit, symbol);
switch (decl->define_decl.define_kind)
{
case DEFINE_IDENT_GENERIC:

View File

@@ -14,10 +14,10 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr);
static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr);
static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl);
static inline void expr_set_as_const_list(Expr *expr, ConstInitializer *list);
static inline bool is_const(Expr *expr);
static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error);
static bool sema_check_stmt_compile_time(SemaContext *context, Ast *ast);
static bool binary_arithmetic_promotion(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type, Expr *parent, const char *error_message);
static inline bool expr_both_const(Expr *left, Expr *right);
static inline void expr_set_as_const_list(Expr *expr, ConstInitializer *list)
{
expr->expr_kind = EXPR_CONST;
@@ -27,16 +27,12 @@ static inline void expr_set_as_const_list(Expr *expr, ConstInitializer *list)
static bool sema_decay_array_pointers(Expr *expr)
{
Type *expr_type = expr->type->canonical;
if (expr_type->type_kind != TYPE_POINTER) return true;
switch (expr_type->pointer->type_kind)
{
case TYPE_ARRAY:
case TYPE_VECTOR:
return cast_implicit(expr, type_get_ptr(expr_type->pointer->array.base));
default:
return true;
}
CanonicalType *pointer_type = type_pointer_type(type_no_fail(expr->type));
if (!pointer_type || !type_is_arraylike(pointer_type)) return true;
return cast_implicit(expr, type_get_opt_fail(type_get_ptr(pointer_type->array.base), IS_FAILABLE(expr)));
}
int BINOP_PREC_REQ[BINARYOP_LAST + 1] =
@@ -71,12 +67,6 @@ static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl)
return embedded_struct;
}
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
static inline bool is_const(Expr *expr)
{
return expr->expr_kind == EXPR_CONST;
}
static inline bool expr_both_const(Expr *left, Expr *right)
{
@@ -271,38 +261,26 @@ static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eva
return true;
}
// Check if the assignment fits
static bool sema_bit_assignment_check(Expr *right, Decl *member)
{
if (right->expr_kind != EXPR_CONST || !type_is_integer(right->type)) return true;
// Don't check non-consts and non integers.
if (!IS_CONST(right) || !type_is_integer(right->type)) return true;
unsigned bits = member->var.end_bit - member->var.start_bit + 1;
if (bits >= type_size(right->type) * 8 || int_is_zero(right->const_expr.ixx)) return true;
// If we have enough bits to fit, then we're done.
if (bits >= type_bit_size(right->type) || int_is_zero(right->const_expr.ixx)) return true;
// Check that we're not assigning consts that will be cut.
TypeKind kind = right->const_expr.ixx.type;
Int128 i = right->const_expr.ixx.i;
int bits_used;
if (type_kind_is_signed(kind))
if (int_bits_needed(right->const_expr.ixx) > bits)
{
if (i128_is_neg(i))
{
i = i128_neg(i);
i = i128_sub64(i, 1);
}
bits_used = (int) (1 + 128 - i128_clz(&i));
SEMA_ERROR(right,
"This constant would be truncated if stored in the bitstruct, do you need a wider bit range?");
return false;
}
else
{
bits_used = (int) (128 - i128_clz(&i));
}
if (bits_used <= bits) return true;
SEMA_ERROR(right,
"This constant would be truncated if stored in the bitstruct, do you need a wider bit range?");
return false;
return true;
}
bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
{
RETRY:
@@ -488,7 +466,7 @@ void expr_insert_deref(Expr *original)
}
static void expr_unify_binary(Expr *expr, Expr *left, Expr *right)
static void expr_unify_binary_failability(Expr *expr, Expr *left, Expr *right)
{
expr->type = type_get_opt_fail(left->type, IS_FAILABLE(right));
}
@@ -792,7 +770,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr)
expr_replace(expr, path ? left : right);
}
expr_unify_binary(expr, left, right);
expr_unify_binary_failability(expr, left, right);
return true;
}
@@ -853,8 +831,6 @@ static inline bool find_possible_inferred_identifier(Type *to, Expr *expr)
}
static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr)
{
Decl *ambiguous_decl = NULL;
@@ -876,6 +852,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
expr->identifier_expr.identifier,
expr->identifier_expr.path,
true);
(void)decl;
assert(!decl_ok(decl));
return false;
}
@@ -910,6 +887,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
{
if (!sema_analyse_decl(context, decl)) return decl_poison(decl);
}
unit_register_external_symbol(context->compilation_unit, decl);
if (decl->decl_kind == DECL_VAR)
{
decl->var.is_read = true;
@@ -2022,7 +2000,6 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
assert(macro);
assert(macro->macro_decl.block_parameter.index);
// TODO handle named arguments
ExprCall *call_expr = &call->call_expr;
if (vec_size(call_expr->body_arguments))
{
@@ -2034,6 +2011,7 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
SEMA_ERROR(call, "Expanding parameters is not allowed for macro invocations.");
return false;
}
// Theoretically we could support named arguments, but that's unnecessary.
unsigned expressions = vec_size(call_expr->arguments);
if (expressions != vec_size(macro->macro_decl.body_parameters))
{
@@ -2070,24 +2048,29 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
return success;
}
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable)
static inline bool sema_analyse_call_attributes(SemaContext *context, Decl *decl, Expr *call_expr)
{
Attr **attributes = call_expr->call_expr.attributes;
int force_inline = -1;
VECEACH(expr->call_expr.attributes, i)
VECEACH(attributes, i)
{
Attr *attr = expr->call_expr.attributes[i];
Attr *attr = attributes[i];
AttributeType attribute = sema_analyse_attribute(context, attr, ATTR_CALL);
if (attribute == ATTRIBUTE_NONE) return expr_poison(expr);
bool had = false;
if (attribute == ATTRIBUTE_NONE) return false;
switch (attribute)
{
case ATTRIBUTE_INLINE:
case ATTRIBUTE_NOINLINE:
if (decl->decl_kind != DECL_FUNC)
if (decl && decl->decl_kind != DECL_FUNC)
{
SEMA_TOKID_ERROR(attr->name, "Inline / noinline attribute is only allowed for direct function/method calls");
return expr_poison(expr);
SEMA_TOKID_ERROR(attr->name,
"Inline / noinline attribute is only allowed for direct function/method calls");
return false;
}
if (force_inline != -1)
{
SEMA_TOKID_ERROR(attr->name, "Only a single inline / noinline attribute is allowed on a call.");
return false;
}
force_inline = attribute == ATTRIBUTE_INLINE ? 1 : 0;
break;
@@ -2095,7 +2078,17 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
UNREACHABLE;
}
}
if (force_inline != -1)
{
call_expr->call_expr.force_inline = force_inline == 1;
call_expr->call_expr.force_noinline = force_inline == 0;
}
return true;
}
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable)
{
expr->call_expr.is_type_method = struct_var != NULL;
if (!sema_analyse_call_attributes(context, decl, expr)) return expr_poison(expr);
if (decl == NULL)
{
return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(expr->call_expr.function->type), failable);
@@ -2125,8 +2118,6 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
return false;
}
expr->call_expr.func_ref = decl;
expr->call_expr.force_inline = force_inline == 1;
expr->call_expr.force_noinline = force_inline == 0;
return sema_expr_analyse_func_call(context, expr, decl, struct_var, failable);
case DECL_GENERIC:
if (is_macro)
@@ -4770,7 +4761,7 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left,
}
// 6. Set the type & other properties.
expr_unify_binary(expr, left, right);
expr_unify_binary_failability(expr, left, right);
return true;
@@ -4953,7 +4944,7 @@ static bool sema_expr_analyse_bit(SemaContext *context, Expr *expr, Expr *left,
}
// 5. Assign the type
expr_unify_binary(expr, left, right);
expr_unify_binary_failability(expr, left, right);
return true;
}
@@ -5122,9 +5113,9 @@ static void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right,
static bool sema_is_unsigned_always_false_comparison(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{
if (context->active_scope.flags & SCOPE_MACRO) return true;
if (!is_const(left) && !is_const(right)) return true;
if (!expr_is_const(left) && !expr_is_const(right)) return true;
if (!type_is_integer(left->type)) return true;
if (is_const(left) && type_is_unsigned(type_flatten_distinct(right->type)))
if (expr_is_const(left) && type_is_unsigned(type_flatten_distinct(right->type)))
{
if (int_is_neg(left->const_expr.ixx))
{
@@ -5146,7 +5137,7 @@ static bool sema_is_unsigned_always_false_comparison(SemaContext *context, Expr
return true;
}
}
if (!is_const(right) || !type_is_unsigned(type_flatten_distinct(left->type))) return true;
if (!expr_is_const(right) || !type_is_unsigned(type_flatten_distinct(left->type))) return true;
if (int_is_neg(right->const_expr.ixx))
{
SEMA_ERROR(right, "Comparing an unsigned value with a negative constant is only allowed inside of macros.");
@@ -5957,7 +5948,7 @@ static inline bool sema_expr_analyse_typeid(SemaContext *context, Expr *expr)
}
static inline bool sema_expr_analyse_expr_block(SemaContext *context, Expr *expr)
static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infer_type, Expr *expr)
{
bool success = true;
expr->type = type_void;
@@ -5965,7 +5956,7 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Expr *expr
Type *prev_expected_block_type = context->expected_block_type;
Ast **saved_returns = context_push_returns(context);
Type *stored_block_type = context->expected_block_type;
context->expected_block_type = NULL;
context->expected_block_type = infer_type;
SCOPE_START_WITH_FLAGS(SCOPE_EXPR_BLOCK)
PUSH_CONTINUE(NULL);
@@ -6934,7 +6925,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
case EXPR_COMPOUND_LITERAL:
return sema_expr_analyse_compound_literal(context, expr);
case EXPR_EXPR_BLOCK:
return sema_expr_analyse_expr_block(context, expr);
return sema_expr_analyse_expr_block(context, NULL, expr);
case EXPR_RETHROW:
return sema_expr_analyse_rethrow(context, expr);
case EXPR_CONST:
@@ -7284,6 +7275,9 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex
case EXPR_DESIGNATED_INITIALIZER_LIST:
if (!sema_expr_analyse_initializer_list(context, infer_type, expr)) return expr_poison(expr);
break;
case EXPR_EXPR_BLOCK:
if (!sema_expr_analyse_expr_block(context, infer_type, expr)) return expr_poison(expr);
break;
case EXPR_CONST_IDENTIFIER:
if (!sema_expr_analyse_identifier(context, infer_type, expr)) return expr_poison(expr);
break;

View File

@@ -52,6 +52,8 @@ void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
#define PUSH_BREAKCONT(ast) PUSH_CONTINUE(ast); PUSH_BREAK(ast)
#define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK()
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
AttributeType sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain domain);
bool expr_is_ltype(Expr *expr);
@@ -71,4 +73,9 @@ bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr);
bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable);
void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value, bool narrowable);
static inline bool expr_is_const(Expr *expr);
static inline bool expr_is_const(Expr *expr)
{
return expr->expr_kind == EXPR_CONST;
}

View File

@@ -239,10 +239,7 @@ static inline Decl *sema_resolve_symbol(SemaContext *context, const char *symbol
sema_report_error_on_decl(symbol_str, span, decl, ambiguous_other_decl, private_decl);
return poisoned_decl;
}
if (decl->module && decl->module != context->unit->module)
{
unit_register_external_symbol(context->compilation_unit, decl);
}
unit_register_external_symbol(context->compilation_unit, decl);
return decl;
}

View File

@@ -61,9 +61,14 @@ static inline bool sema_analyse_block_return_stmt(SemaContext *context, Ast *sta
context->active_scope.jump_end = true;
if (statement->return_stmt.expr)
{
if (!sema_analyse_expr(context, statement->return_stmt.expr))
Type *block_type = context->expected_block_type;
if (block_type)
{
return false;
if (!sema_analyse_expr_rhs(context, block_type, statement->return_stmt.expr, type_is_failable(block_type))) return false;
}
else
{
if (!sema_analyse_expr(context, statement->return_stmt.expr)) return false;
}
}
vec_add(context->returns, statement);

View File

@@ -1552,9 +1552,10 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_ERRTYPE:
if (other->type_kind == TYPE_ERRTYPE) return type_anyerr;
return NULL;
case TYPE_ANYERR:
return type_anyerr;
case TYPE_FUNC:
case TYPE_UNION:
case TYPE_ANYERR:
case TYPE_TYPEID:
case TYPE_STRUCT:
case TYPE_UNTYPED_LIST:

View File

@@ -1,6 +1,6 @@
macro int frob()
{
return 0.0; // #error: Expected 'int', not 'double'.
return 0.0; // #error: Implicitly casting 'double' to 'int' is not permitted
}
fn void test1()