Forráskód Böngészése

Unexported struct fields

Ginger Bill 8 éve
szülő
commit
6fdcbefe5d
5 módosított fájl, 50 hozzáadás és 26 törlés
  1. 0 7
      code/demo.odin
  2. 2 0
      core/fmt.odin
  3. 45 19
      src/check_expr.c
  4. 2 0
      src/checker.c
  5. 1 0
      src/entity.c

+ 0 - 7
code/demo.odin

@@ -8,13 +8,6 @@
 #import "halloc.odin";
 
 main :: proc() {
-
-	m: map[int]int;
-	m[123] = 312;
-	fmt.println(m[123]);
-	delete(m, 123);
-	fmt.println(m[123]);
-
 /*
 /*
 	Version 0.1.1

+ 2 - 0
core/fmt.odin

@@ -11,6 +11,8 @@ Buffer :: struct {
 	length: int,
 }
 
+
+
 buffer_write :: proc(buf: ^Buffer, b: []byte) {
 	if buf.length < buf.data.count {
 		n := min(buf.data.count-buf.length, b.count);

+ 45 - 19
src/check_expr.c

@@ -2564,15 +2564,16 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
 	return true;
 }
 
-isize procedure_overload_count(Scope *s, String name) {
-	isize overload_count = 0;
+isize entity_overload_count(Scope *s, String name) {
 	Entity *e = scope_lookup_entity(s, name);
+	if (e == NULL) {
+		return 0;
+	}
 	if (e->kind == Entity_Procedure) {
-		HashKey key = hash_string(e->token.string);
 		// NOTE(bill): Overloads are only allowed with the same scope
-		overload_count = map_entity_multi_count(&s->elements, key);
+		return map_entity_multi_count(&s->elements, hash_string(e->token.string));
 	}
-	return overload_count;
+	return 1;
 }
 
 Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
@@ -2596,8 +2597,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	}
 
 	if (op_expr->kind == AstNode_Ident) {
-		String name = op_expr->Ident.string;
-		Entity *e = scope_lookup_entity(c->context.scope, name);
+		String op_name = op_expr->Ident.string;
+		Entity *e = scope_lookup_entity(c->context.scope, op_name);
 
 		add_entity_use(c, op_expr, e);
 		expr_entity = e;
@@ -2606,29 +2607,30 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 			// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
 			// It pretty much needs to be in this order and this way
 			// If you can clean this up, please do but be really careful
-
+			String import_name = op_name;
 			Scope *import_scope = e->ImportName.scope;
-
-			String sel_name = selector->Ident.string;
+			String entity_name = selector->Ident.string;
 
 			check_op_expr = false;
-			entity = scope_lookup_entity(import_scope, sel_name);
+			entity = scope_lookup_entity(import_scope, entity_name);
 			bool is_declared = entity != NULL;
 			if (is_declared) {
 				if (entity->kind == Entity_Builtin) {
+					// NOTE(bill): Builtin's are in the universe scope which is part of every scopes hierarchy
+					// This means that we should just ignore the found result through it
 					is_declared = false;
 				} else if (entity->scope->is_global && !import_scope->is_global) {
 					is_declared = false;
 				}
 			}
 			if (!is_declared) {
-				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
+				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(entity_name), LIT(import_name));
 				goto error;
 			}
 			check_entity_decl(c, entity, NULL, NULL);
 			GB_ASSERT(entity->type != NULL);
 
-			isize overload_count = procedure_overload_count(import_scope, entity->token.string);
+			isize overload_count = entity_overload_count(import_scope, entity_name);
 			bool is_overloaded = overload_count > 1;
 
 			bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL;
@@ -2641,18 +2643,17 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 			if (is_not_exported) {
 				gbString sel_str = expr_to_string(selector);
-				error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
+				error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(import_name));
 				gb_string_free(sel_str);
 				goto error;
 			}
 
 			if (is_overloaded) {
-				HashKey key = hash_string(entity->token.string);
-				Scope *s = import_scope;
+				HashKey key = hash_string(entity_name);
 				bool skip = false;
 
 				Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
-				map_entity_multi_get_all(&s->elements, key, procs);
+				map_entity_multi_get_all(&import_scope->elements, key, procs);
 				for (isize i = 0; i < overload_count; i++) {
 					Type *t = base_type(procs[i]->type);
 					if (t == t_invalid) {
@@ -2660,7 +2661,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 					}
 
 					// NOTE(bill): Check to see if it's imported
-					if (map_bool_get(&e->ImportName.scope->implicit, hash_pointer(procs[i]))) {
+					if (map_bool_get(&import_scope->implicit, hash_pointer(procs[i]))) {
 						gb_swap(Entity *, procs[i], procs[overload_count-1]);
 						overload_count--;
 						i--; // NOTE(bill): Counteract the post event
@@ -4464,10 +4465,23 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 						String name = fv->field->Ident.string;
 
 						Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
-						if (sel.entity == NULL) {
+						bool is_unknown = sel.entity == NULL;
+						if (is_unknown) {
 							error_node(elem, "Unknown field `%.*s` in structure literal", LIT(name));
 							continue;
 						}
+						if (!is_unknown) {
+							Entity *f = sel.entity;
+							Scope *file_scope = f->scope;
+							while (!file_scope->is_file) {
+								file_scope = file_scope->parent;
+							}
+							if (!is_entity_exported(f) && file_scope != c->context.file_scope) {
+								error_node(elem, "Cannot assign to an unexported field `%.*s` in structure literal", LIT(name));
+								continue;
+							}
+						}
+
 
 						if (sel.index.count > 1) {
 							error_node(elem, "Cannot assign to an anonymous field `%.*s` in a structure literal (at the moment)", LIT(name));
@@ -4510,6 +4524,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 							break;
 						}
 
+						Scope *file_scope = field->scope;
+						while (!file_scope->is_file) {
+							file_scope = file_scope->parent;
+						}
+						if (!is_entity_exported(field) && file_scope != c->context.file_scope) {
+							gbString t = type_to_string(type);
+							error_node(o->expr, "Implicit assignment to an unexported field `%.*s` in `%s` literal",
+							           LIT(field->token.string), t);
+							gb_string_free(t);
+							continue;
+						}
+
 						if (base_type(field->type) == t_any) {
 							is_constant = false;
 						}

+ 2 - 0
src/checker.c

@@ -261,6 +261,7 @@ typedef struct DelayedDecl {
 } DelayedDecl;
 
 typedef struct CheckerContext {
+	Scope *    file_scope;
 	Scope *    scope;
 	DeclInfo * decl;
 	u32        stmt_state_flags;
@@ -1018,6 +1019,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
 		c->curr_ast_file = file;
 		c->context.decl  = file->decl_info;
 		c->context.scope = file->scope;
+		c->context.file_scope = file->scope;
 	}
 }
 

+ 1 - 0
src/entity.c

@@ -113,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) {
 }
 
 bool is_entity_exported(Entity *e) {
+	// TODO(bill): Determine the actual exportation rules for imports of entities
 	GB_ASSERT(e != NULL);
 	if (!is_entity_kind_exported(e->kind)) {
 		return false;