Commit 7f90dbbb11

Andrew Kelley <superjoe30@gmail.com>
2016-05-15 09:25:13
switch on compile var marks entire namespaces
as depending on compile vars. closes #154
1 parent 6ae6b5f
Changed files (4)
src/analyze.cpp
@@ -30,13 +30,15 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
 static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node);
 static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
-static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn);
-static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type);
+static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
+        bool depends_on_compile_var);
+static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
+        bool depends_on_compile_var);
 static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
         TypeTableEntry *expected_type, uint64_t x);
 static AstNode *find_decl(BlockContext *context, Buf *name);
 static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
-        bool pointer_only, BlockContext *block_context);
+        bool pointer_only, BlockContext *block_context, bool depends_on_compile_var);
 static TopLevelDecl *get_as_top_level_decl(AstNode *node);
 static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
         BlockContext *context, AstNode *source_node,
@@ -2587,7 +2589,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
 
                 node->data.field_access_expr.is_member_fn = true;
                 FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
-                return resolve_expr_const_val_as_fn(g, node, fn_entry);
+                return resolve_expr_const_val_as_fn(g, node, fn_entry, false);
             } else {
                 add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",
                     buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
@@ -2642,7 +2644,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
             AstNode *decl_node = entry ? entry->value : nullptr;
             if (decl_node) {
                 bool pointer_only = false;
-                return analyze_decl_ref(g, node, decl_node, pointer_only, context);
+                return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
             } else {
                 add_node_error(g, node,
                     buf_sprintf("container '%s' has no member called '%s'",
@@ -2652,7 +2654,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
         } else if (child_type->id == TypeTableEntryIdPureError) {
             return analyze_error_literal_expr(g, import, context, node, field_name);
         } else if (wrapped_in_fn_call) { // this branch should go last, before the error in the else case
-            return resolve_expr_const_val_as_type(g, node, child_type);
+            return resolve_expr_const_val_as_type(g, node, child_type, false);
         } else {
             add_node_error(g, node,
                 buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
@@ -2671,7 +2673,8 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
                 add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
             }
             bool pointer_only = false;
-            return analyze_decl_ref(g, node, decl_node, pointer_only, context);
+            return analyze_decl_ref(g, node, decl_node, pointer_only, context,
+                    const_val->depends_on_compile_var);
         } else {
             const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
             add_node_error(g, node,
@@ -2770,33 +2773,44 @@ static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node)
     return g->builtin_types.entry_void;
 }
 
-static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) {
+static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type,
+        bool depends_on_compile_var)
+{
     Expr *expr = get_resolved_expr(node);
     expr->const_val.ok = true;
     expr->const_val.data.x_type = type;
+    expr->const_val.depends_on_compile_var = depends_on_compile_var;
     return g->builtin_types.entry_type;
 }
 
-static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) {
+static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other,
+        bool depends_on_compile_var)
+{
     Expr *expr = get_resolved_expr(node);
     Expr *other_expr = get_resolved_expr(other);
     expr->const_val = other_expr->const_val;
+    expr->const_val.depends_on_compile_var = expr->const_val.depends_on_compile_var ||
+        depends_on_compile_var;
     return other_expr->type_entry;
 }
 
-static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) {
+static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn,
+        bool depends_on_compile_var)
+{
     Expr *expr = get_resolved_expr(node);
     expr->const_val.ok = true;
     expr->const_val.data.x_fn = fn;
+    expr->const_val.depends_on_compile_var = depends_on_compile_var;
     return fn->type_entry;
 }
 
 static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode *node,
-        TypeTableEntry *type_entry)
+        TypeTableEntry *type_entry, bool depends_on_compile_var)
 {
     Expr *expr = get_resolved_expr(node);
     expr->const_val.ok = true;
     expr->const_val.data.x_type = type_entry;
+    expr->const_val.depends_on_compile_var = depends_on_compile_var;
     return type_entry;
 }
 
@@ -2922,7 +2936,7 @@ static bool var_is_pure(VariableTableEntry *var, BlockContext *context) {
 }
 
 static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
-        BlockContext *context)
+        BlockContext *context, bool depends_on_compile_var)
 {
     get_resolved_expr(source_node)->variable = var;
     if (!var_is_pure(var, context)) {
@@ -2931,14 +2945,15 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
     if (var->is_const && var->val_node) {
         ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
         if (other_const_val->ok) {
-            return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node);
+            return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
+                    depends_on_compile_var);
         }
     }
     return var->type;
 }
 
 static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
-        bool pointer_only, BlockContext *block_context)
+        bool pointer_only, BlockContext *block_context, bool depends_on_compile_var)
 {
     resolve_top_level_decl(g, decl_node, pointer_only);
     TopLevelDecl *tld = get_as_top_level_decl(decl_node);
@@ -2948,27 +2963,29 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
 
     if (decl_node->type == NodeTypeVariableDeclaration) {
         VariableTableEntry *var = decl_node->data.variable_declaration.variable;
-        return analyze_var_ref(g, source_node, var, block_context);
+        return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var);
     } else if (decl_node->type == NodeTypeFnProto) {
         if (decl_node->data.fn_proto.generic_params.length > 0) {
             TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
             assert(type_entry);
-            return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry);
+            return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
         } else {
             FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
             assert(fn_entry->type_entry);
-            return resolve_expr_const_val_as_fn(g, source_node, fn_entry);
+            return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var);
         }
     } else if (decl_node->type == NodeTypeStructDecl) {
         if (decl_node->data.struct_decl.generic_params.length > 0) {
             TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type;
             assert(type_entry);
-            return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry);
+            return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var);
         } else {
-            return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry);
+            return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry,
+                    depends_on_compile_var);
         }
     } else if (decl_node->type == NodeTypeTypeDecl) {
-        return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry);
+        return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry,
+                depends_on_compile_var);
     } else {
         zig_unreachable();
     }
@@ -2978,25 +2995,25 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
         TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
 {
     if (node->data.symbol_expr.override_type_entry) {
-        return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry);
+        return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry, false);
     }
 
     Buf *variable_name = &node->data.symbol_expr.symbol;
 
     auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
     if (primitive_table_entry) {
-        return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value);
+        return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value, false);
     }
 
     VariableTableEntry *var = find_variable(g, context, variable_name);
     if (var) {
-        TypeTableEntry *var_type = analyze_var_ref(g, node, var, context);
+        TypeTableEntry *var_type = analyze_var_ref(g, node, var, context, false);
         return var_type;
     }
 
     AstNode *decl_node = find_decl(context, variable_name);
     if (decl_node) {
-        return analyze_decl_ref(g, node, decl_node, pointer_only, context);
+        return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
     }
 
     if (import->any_imports_failed) {
@@ -3819,11 +3836,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
                 return g->builtin_types.entry_invalid;
             } else {
                 return resolve_expr_const_val_as_type(g, node,
-                        get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint));
+                        get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
             }
         } else if (context->fn_entry) {
             return resolve_expr_const_val_as_type(g, node,
-                    get_slice_type(g, child_type, node->data.array_type.is_const));
+                    get_slice_type(g, child_type, node->data.array_type.is_const), false);
         } else {
             add_node_error(g, first_executing_node(size_node),
                     buf_sprintf("unable to evaluate constant expression"));
@@ -3831,7 +3848,7 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
         }
     } else {
         return resolve_expr_const_val_as_type(g, node,
-                get_slice_type(g, child_type, node->data.array_type.is_const));
+                get_slice_type(g, child_type, node->data.array_type.is_const), false);
     }
 }
 
@@ -3844,7 +3861,7 @@ static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *impor
         return type_entry;
     }
 
-    return resolve_expr_const_val_as_type(g, node, type_entry);
+    return resolve_expr_const_val_as_type(g, node, type_entry, false);
 }
 
 static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -4973,7 +4990,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                     case TypeTableEntryIdUnion:
                     case TypeTableEntryIdFn:
                     case TypeTableEntryIdTypeDecl:
-                        return resolve_expr_const_val_as_type(g, node, type_entry);
+                        return resolve_expr_const_val_as_type(g, node, type_entry, false);
                 }
             }
         case BuiltinFnIdCInclude:
@@ -5307,10 +5324,10 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
         AstNode *impl_decl_node = entry->value;
         if (impl_decl_node->type == NodeTypeFnProto) {
             FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
-            return resolve_expr_const_val_as_fn(g, node, fn_table_entry);
+            return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
         } else if (impl_decl_node->type == NodeTypeStructDecl) {
             TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
-            return resolve_expr_const_val_as_type(g, node, type_entry);
+            return resolve_expr_const_val_as_type(g, node, type_entry, false);
         } else {
             zig_unreachable();
         }
@@ -5324,14 +5341,14 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
         preview_fn_proto_instance(g, import, impl_decl_node, child_context);
         g->generic_table.put(generic_fn_type_id, impl_decl_node);
         FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry;
-        return resolve_expr_const_val_as_fn(g, node, fn_table_entry);
+        return resolve_expr_const_val_as_fn(g, node, fn_table_entry, false);
     } else if (decl_node->type == NodeTypeStructDecl) {
         AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
         g->generic_table.put(generic_fn_type_id, impl_decl_node);
         scan_struct_decl(g, import, child_context, impl_decl_node);
         TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
         resolve_struct_type(g, import, type_entry);
-        return resolve_expr_const_val_as_type(g, node, type_entry);
+        return resolve_expr_const_val_as_type(g, node, type_entry, false);
     } else {
         zig_unreachable();
     }
@@ -5480,7 +5497,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
                         return g->builtin_types.entry_invalid;
                     } else {
                         return resolve_expr_const_val_as_type(g, node,
-                                get_pointer_to_type(g, meta_type, is_const));
+                                get_pointer_to_type(g, meta_type, is_const), false);
                     }
                 } else if (child_type->id == TypeTableEntryIdNumLitInt ||
                            child_type->id == TypeTableEntryIdNumLitFloat)
@@ -5520,7 +5537,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
                         add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in maybe type"));
                         return g->builtin_types.entry_invalid;
                     } else {
-                        return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));
+                        return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type), false);
                     }
                 } else if (type_entry->id == TypeTableEntryIdUnreachable) {
                     add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in maybe type"));
@@ -5548,7 +5565,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
                         add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type"));
                         return g->builtin_types.entry_invalid;
                     } else {
-                        return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type));
+                        return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type), false);
                     }
                 } else if (type_entry->id == TypeTableEntryIdUnreachable) {
                     add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in error type"));
@@ -6159,10 +6176,10 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
             return_type = analyze_fn_proto_expr(g, import, context, expected_type, node);
             break;
         case NodeTypeErrorType:
-            return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
+            return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error, false);
             break;
         case NodeTypeTypeLiteral:
-            return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_type);
+            return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_type, false);
             break;
         case NodeTypeSwitchExpr:
             return_type = analyze_switch_expr(g, import, context, expected_type, node);
test/a.zig
@@ -0,0 +1,1 @@
+pub const a_bool = true;
test/b.zig
@@ -0,0 +1,1 @@
+pub const a_bool = false;
test/self_hosted.zig
@@ -1656,3 +1656,17 @@ fn use_generic_param_in_generic_param() {
 fn a_generic_fn(T: type, a: T)(b: T) -> T {
     return a + b;
 }
+
+
+#attribute("test")
+fn namespace_depends_on_compile_var() {
+    if (some_namespace.a_bool) {
+        assert(some_namespace.a_bool);
+    } else {
+        assert(!some_namespace.a_bool);
+    }
+}
+const some_namespace = switch(@compile_var("os")) {
+    linux => @import("a.zig"),
+    else => @import("b.zig"),
+};