authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-19 16:56:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-19 16:56:44-04:00
logaf8661405b908c0abfc191501a8ad1a59a54e86a
treed76bde495229dc37b7436c547afe5f03aee6b61d
parent1d07bbbef23993338b231fbd9d7bbf5a349c5f31
signature Commit is signed but in an unrecognized format.

fix usingnamespace

It used to be that usingnamespace was only allowed at top level. This made it OK to put the state inside the AST node data structure. However, now usingnamespace can occur inside any aggregate data structure, and therefore the state must be in the TopLevelDeclaration rather than in the AST node. There were two other problems with the usingnamespace implementation: * It was passing the wrong destination ScopeDecl, so it could cause an incorrect error such as "import of file outside package path". * When doing `usingnamespace` on a file that already had `pub usingnamespace` in it would "steal" the usingnamespace, causing incorrect "use of undeclared identifier" errors in the target file. closes #2632 closes #2580

9 files changed, 170 insertions(+), 145 deletions(-)

src/all_types.hpp+9-7
......@@ -366,6 +366,7 @@ enum TldId {
366366 TldIdFn,
367367 TldIdContainer,
368368 TldIdCompTime,
369 TldIdUsingNamespace,
369370};
370371
371372enum TldResolution {
......@@ -413,6 +414,12 @@ struct TldCompTime {
413414 Tld base;
414415};
415416
417struct TldUsingNamespace {
418 Tld base;
419
420 ConstExprValue *using_namespace_value;
421};
422
416423struct TypeEnumField {
417424 Buf *name;
418425 BigInt value;
......@@ -453,7 +460,7 @@ enum NodeType {
453460 NodeTypeFieldAccessExpr,
454461 NodeTypePtrDeref,
455462 NodeTypeUnwrapOptional,
456 NodeTypeUse,
463 NodeTypeUsingNamespace,
457464 NodeTypeBoolLiteral,
458465 NodeTypeNullLiteral,
459466 NodeTypeUndefinedLiteral,
......@@ -715,9 +722,6 @@ struct AstNodeArrayType {
715722struct AstNodeUsingNamespace {
716723 VisibMod visib_mod;
717724 AstNode *expr;
718
719 TldResolution resolution;
720 ConstExprValue *using_namespace_value;
721725};
722726
723727struct AstNodeIfBoolExpr {
......@@ -1745,8 +1749,6 @@ struct CodeGen {
17451749
17461750 ZigList<Tld *> resolve_queue;
17471751 size_t resolve_queue_index;
1748 ZigList<AstNode *> use_queue;
1749 size_t use_queue_index;
17501752 ZigList<TimeEvent> timing_events;
17511753 ZigList<AstNode *> tld_ref_source_node_stack;
17521754 ZigList<ZigFn *> inline_fns;
......@@ -2005,7 +2007,7 @@ struct ScopeDecls {
20052007 Scope base;
20062008
20072009 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
2008 ZigList<AstNode *> use_decls;
2010 ZigList<TldUsingNamespace *> use_decls;
20092011 AstNode *safety_set_node;
20102012 AstNode *fast_math_set_node;
20112013 ZigType *import;
src/analyze.cpp+137-128
......@@ -28,6 +28,8 @@ static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *uni
2828static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type);
2929static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
3030static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
31static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
32static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
3133
3234static bool is_top_level_struct(ZigType *import) {
3335 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
......@@ -2854,6 +2856,8 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
28542856 add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body"));
28552857 return;
28562858 }
2859 } else if (tld->id == TldIdUsingNamespace) {
2860 g->resolve_queue.append(tld);
28572861 }
28582862 if (is_export) {
28592863 g->resolve_queue.append(tld);
......@@ -2867,7 +2871,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
28672871 }
28682872 }
28692873
2870 {
2874 if (tld->name != nullptr) {
28712875 auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
28722876 if (entry) {
28732877 Tld *other_tld = entry->value;
......@@ -2875,9 +2879,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
28752879 add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
28762880 return;
28772881 }
2878 }
28792882
2880 {
28812883 ZigType *type;
28822884 if (get_primitive_type(g, tld->name, &type) != ErrorPrimitiveTypeNotFound) {
28832885 add_node_error(g, tld->source_node,
......@@ -2977,12 +2979,14 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
29772979
29782980 break;
29792981 }
2980 case NodeTypeUse:
2981 {
2982 g->use_queue.append(node);
2983 decls_scope->use_decls.append(node);
2984 break;
2985 }
2982 case NodeTypeUsingNamespace: {
2983 VisibMod visib_mod = node->data.using_namespace.visib_mod;
2984 TldUsingNamespace *tld_using_namespace = allocate<TldUsingNamespace>(1);
2985 init_tld(&tld_using_namespace->base, TldIdUsingNamespace, nullptr, visib_mod, node, &decls_scope->base);
2986 add_top_level_decl(g, decls_scope, &tld_using_namespace->base);
2987 decls_scope->use_decls.append(tld_using_namespace);
2988 break;
2989 }
29862990 case NodeTypeTestDecl:
29872991 preview_test_decl(g, node, decls_scope);
29882992 break;
......@@ -3266,6 +3270,117 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
32663270 g->global_vars.append(tld_var);
32673271}
32683272
3273static void add_symbols_from_container(CodeGen *g, TldUsingNamespace *src_using_namespace,
3274 TldUsingNamespace *dst_using_namespace, ScopeDecls* dest_decls_scope)
3275{
3276 if (src_using_namespace->base.resolution == TldResolutionUnresolved ||
3277 src_using_namespace->base.resolution == TldResolutionResolving)
3278 {
3279 assert(src_using_namespace->base.parent_scope->id == ScopeIdDecls);
3280 ScopeDecls *src_decls_scope = (ScopeDecls *)src_using_namespace->base.parent_scope;
3281 preview_use_decl(g, src_using_namespace, src_decls_scope);
3282 if (src_using_namespace != dst_using_namespace) {
3283 resolve_use_decl(g, src_using_namespace, src_decls_scope);
3284 }
3285 }
3286
3287 ConstExprValue *use_expr = src_using_namespace->using_namespace_value;
3288 if (type_is_invalid(use_expr->type)) {
3289 dest_decls_scope->any_imports_failed = true;
3290 return;
3291 }
3292
3293 dst_using_namespace->base.resolution = TldResolutionOk;
3294
3295 assert(use_expr->special != ConstValSpecialRuntime);
3296
3297 // The source scope for the imported symbols
3298 ScopeDecls *src_scope = get_container_scope(use_expr->data.x_type);
3299 // The top-level container where the symbols are defined, it's used in the
3300 // loop below in order to exclude the ones coming from an import statement
3301 ZigType *src_import = get_scope_import(&src_scope->base);
3302 assert(src_import != nullptr);
3303
3304 if (src_scope->any_imports_failed) {
3305 dest_decls_scope->any_imports_failed = true;
3306 }
3307
3308 auto it = src_scope->decl_table.entry_iterator();
3309 for (;;) {
3310 auto *entry = it.next();
3311 if (!entry)
3312 break;
3313
3314 Buf *target_tld_name = entry->key;
3315 Tld *target_tld = entry->value;
3316
3317 if (target_tld->visib_mod == VisibModPrivate) {
3318 continue;
3319 }
3320
3321 if (target_tld->import != src_import) {
3322 continue;
3323 }
3324
3325 auto existing_entry = dest_decls_scope->decl_table.put_unique(target_tld_name, target_tld);
3326 if (existing_entry) {
3327 Tld *existing_decl = existing_entry->value;
3328 if (existing_decl != target_tld) {
3329 ErrorMsg *msg = add_node_error(g, dst_using_namespace->base.source_node,
3330 buf_sprintf("import of '%s' overrides existing definition",
3331 buf_ptr(target_tld_name)));
3332 add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
3333 add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
3334 }
3335 }
3336 }
3337
3338 for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
3339 TldUsingNamespace *tld_using_namespace = src_scope->use_decls.at(i);
3340 if (tld_using_namespace->base.visib_mod != VisibModPrivate)
3341 add_symbols_from_container(g, tld_using_namespace, dst_using_namespace, dest_decls_scope);
3342 }
3343}
3344
3345static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope) {
3346 if (tld_using_namespace->base.resolution == TldResolutionOk ||
3347 tld_using_namespace->base.resolution == TldResolutionInvalid)
3348 {
3349 return;
3350 }
3351 add_symbols_from_container(g, tld_using_namespace, tld_using_namespace, dest_decls_scope);
3352}
3353
3354static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) {
3355 if (using_namespace->base.resolution == TldResolutionOk ||
3356 using_namespace->base.resolution == TldResolutionInvalid)
3357 {
3358 return;
3359 }
3360
3361 using_namespace->base.resolution = TldResolutionResolving;
3362 assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace);
3363 ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base,
3364 using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
3365 using_namespace->using_namespace_value = result;
3366
3367 if (type_is_invalid(result->type)) {
3368 dest_decls_scope->any_imports_failed = true;
3369 using_namespace->base.resolution = TldResolutionInvalid;
3370 using_namespace->using_namespace_value = &g->invalid_instruction->value;
3371 return;
3372 }
3373
3374 if (!is_container(result->data.x_type)) {
3375 add_node_error(g, using_namespace->base.source_node,
3376 buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name)));
3377 dest_decls_scope->any_imports_failed = true;
3378 using_namespace->base.resolution = TldResolutionInvalid;
3379 using_namespace->using_namespace_value = &g->invalid_instruction->value;
3380 return;
3381 }
3382}
3383
32693384void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
32703385 if (tld->resolution != TldResolutionUnresolved)
32713386 return;
......@@ -3299,6 +3414,14 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
32993414 resolve_decl_comptime(g, tld_comptime);
33003415 break;
33013416 }
3417 case TldIdUsingNamespace: {
3418 TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld;
3419 assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls);
3420 ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope;
3421 preview_use_decl(g, tld_using_namespace, dest_decls_scope);
3422 resolve_use_decl(g, tld_using_namespace, dest_decls_scope);
3423 break;
3424 }
33023425 }
33033426
33043427 tld->resolution = TldResolutionOk;
......@@ -3308,10 +3431,10 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
33083431Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
33093432 // resolve all the using_namespace decls
33103433 for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
3311 AstNode *use_decl_node = decls_scope->use_decls.at(i);
3312 if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
3313 preview_use_decl(g, use_decl_node, decls_scope);
3314 resolve_use_decl(g, use_decl_node, decls_scope);
3434 TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i);
3435 if (tld_using_namespace->base.resolution == TldResolutionUnresolved) {
3436 preview_use_decl(g, tld_using_namespace, decls_scope);
3437 resolve_use_decl(g, tld_using_namespace, decls_scope);
33153438 }
33163439 }
33173440
......@@ -3752,110 +3875,6 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
37523875 analyze_fn_ir(g, fn_table_entry, return_type_node);
37533876}
37543877
3755static void add_symbols_from_container(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node, ScopeDecls* decls_scope) {
3756 if (src_use_node->data.using_namespace.resolution == TldResolutionUnresolved) {
3757 preview_use_decl(g, src_use_node, decls_scope);
3758 }
3759
3760 ConstExprValue *use_expr = src_use_node->data.using_namespace.using_namespace_value;
3761 if (type_is_invalid(use_expr->type)) {
3762 decls_scope->any_imports_failed = true;
3763 return;
3764 }
3765
3766 dst_use_node->data.using_namespace.resolution = TldResolutionOk;
3767
3768 assert(use_expr->special != ConstValSpecialRuntime);
3769
3770 // The source struct for the imported symbols
3771 ZigType *src_ty = use_expr->data.x_type;
3772 assert(src_ty);
3773
3774 if (!is_container(src_ty)) {
3775 add_node_error(g, dst_use_node,
3776 buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&src_ty->name)));
3777 decls_scope->any_imports_failed = true;
3778 return;
3779 }
3780
3781 // The source scope for the imported symbols
3782 ScopeDecls *src_scope = get_container_scope(src_ty);
3783 // The top-level container where the symbols are defined, it's used in the
3784 // loop below in order to exclude the ones coming from an import statement
3785 ZigType *src_import = get_scope_import(&src_scope->base);
3786 assert(src_import != nullptr);
3787
3788 if (src_scope->any_imports_failed) {
3789 decls_scope->any_imports_failed = true;
3790 }
3791
3792 auto it = src_scope->decl_table.entry_iterator();
3793 for (;;) {
3794 auto *entry = it.next();
3795 if (!entry)
3796 break;
3797
3798 Buf *target_tld_name = entry->key;
3799 Tld *target_tld = entry->value;
3800
3801 if (target_tld->visib_mod == VisibModPrivate) {
3802 continue;
3803 }
3804
3805 if (target_tld->import != src_import) {
3806 continue;
3807 }
3808
3809 auto existing_entry = decls_scope->decl_table.put_unique(target_tld_name, target_tld);
3810 if (existing_entry) {
3811 Tld *existing_decl = existing_entry->value;
3812 if (existing_decl != target_tld) {
3813 ErrorMsg *msg = add_node_error(g, dst_use_node,
3814 buf_sprintf("import of '%s' overrides existing definition",
3815 buf_ptr(target_tld_name)));
3816 add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
3817 add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
3818 }
3819 }
3820 }
3821
3822 for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
3823 AstNode *use_decl_node = src_scope->use_decls.at(i);
3824 if (use_decl_node->data.using_namespace.visib_mod != VisibModPrivate)
3825 add_symbols_from_container(g, use_decl_node, dst_use_node, decls_scope);
3826 }
3827}
3828
3829void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
3830 assert(node->type == NodeTypeUse);
3831
3832 if (node->data.using_namespace.resolution == TldResolutionOk ||
3833 node->data.using_namespace.resolution == TldResolutionInvalid)
3834 {
3835 return;
3836 }
3837 add_symbols_from_container(g, node, node, decls_scope);
3838}
3839
3840void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
3841 assert(node->type == NodeTypeUse);
3842
3843 if (node->data.using_namespace.resolution == TldResolutionOk ||
3844 node->data.using_namespace.resolution == TldResolutionInvalid)
3845 {
3846 return;
3847 }
3848
3849 node->data.using_namespace.resolution = TldResolutionResolving;
3850 ConstExprValue *result = analyze_const_value(g, &decls_scope->base,
3851 node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
3852
3853 if (type_is_invalid(result->type))
3854 decls_scope->any_imports_failed = true;
3855
3856 node->data.using_namespace.using_namespace_value = result;
3857}
3858
38593878ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code,
38603879 SourceKind source_kind)
38613880{
......@@ -3975,18 +3994,8 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
39753994
39763995void semantic_analyze(CodeGen *g) {
39773996 while (g->resolve_queue_index < g->resolve_queue.length ||
3978 g->fn_defs_index < g->fn_defs.length ||
3979 g->use_queue_index < g->use_queue.length)
3997 g->fn_defs_index < g->fn_defs.length)
39803998 {
3981 for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
3982 AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
3983 // Get the top-level scope where `using_namespace` is used
3984 ScopeDecls *decls_scope = get_container_scope(use_decl_node->owner);
3985 if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
3986 preview_use_decl(g, use_decl_node, decls_scope);
3987 resolve_use_decl(g, use_decl_node, decls_scope);
3988 }
3989 }
39903999 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
39914000 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
39924001 AstNode *source_node = nullptr;
src/analyze.hpp-2
......@@ -86,8 +86,6 @@ bool is_array_ref(ZigType *type_entry);
8686bool is_container_ref(ZigType *type_entry);
8787bool is_valid_vector_elem_type(ZigType *elem_type);
8888void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
89void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
90void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
9189ZigFn *scope_fn_entry(Scope *scope);
9290ZigPackage *scope_package(Scope *scope);
9391ZigType *get_scope_import(Scope *scope);
src/ast_render.cpp+4-4
......@@ -193,8 +193,8 @@ static const char *node_type_str(NodeType node_type) {
193193 return "Symbol";
194194 case NodeTypePrefixOpExpr:
195195 return "PrefixOpExpr";
196 case NodeTypeUse:
197 return "Use";
196 case NodeTypeUsingNamespace:
197 return "UsingNamespace";
198198 case NodeTypeBoolLiteral:
199199 return "BoolLiteral";
200200 case NodeTypeNullLiteral:
......@@ -791,7 +791,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
791791 AstNode *decls_node = node->data.container_decl.decls.at(decl_i);
792792 render_node_grouped(ar, decls_node);
793793
794 if (decls_node->type == NodeTypeUse ||
794 if (decls_node->type == NodeTypeUsingNamespace ||
795795 decls_node->type == NodeTypeVariableDeclaration ||
796796 decls_node->type == NodeTypeFnProto)
797797 {
......@@ -1170,7 +1170,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
11701170 case NodeTypeParamDecl:
11711171 case NodeTypeTestDecl:
11721172 case NodeTypeStructField:
1173 case NodeTypeUse:
1173 case NodeTypeUsingNamespace:
11741174 zig_panic("TODO more ast rendering");
11751175 }
11761176}
src/ir.cpp+2-1
......@@ -8430,7 +8430,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
84308430 switch (node->type) {
84318431 case NodeTypeStructValueField:
84328432 case NodeTypeParamDecl:
8433 case NodeTypeUse:
8433 case NodeTypeUsingNamespace:
84348434 case NodeTypeSwitchProng:
84358435 case NodeTypeSwitchRange:
84368436 case NodeTypeStructField:
......@@ -17847,6 +17847,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_
1784717847 switch (tld->id) {
1784817848 case TldIdContainer:
1784917849 case TldIdCompTime:
17850 case TldIdUsingNamespace:
1785017851 zig_unreachable();
1785117852 case TldIdVar:
1785217853 {
src/parser.cpp+2-2
......@@ -676,7 +676,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) {
676676 AstNode *expr = ast_expect(pc, ast_parse_expr);
677677 expect_token(pc, TokenIdSemicolon);
678678
679 AstNode *res = ast_create_node(pc, NodeTypeUse, usingnamespace);
679 AstNode *res = ast_create_node(pc, NodeTypeUsingNamespace, usingnamespace);
680680 res->data.using_namespace.visib_mod = visib_mod;
681681 res->data.using_namespace.expr = expr;
682682 return res;
......@@ -2938,7 +2938,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29382938 case NodeTypeUnwrapOptional:
29392939 visit_field(&node->data.unwrap_optional.expr, visit, context);
29402940 break;
2941 case NodeTypeUse:
2941 case NodeTypeUsingNamespace:
29422942 visit_field(&node->data.using_namespace.expr, visit, context);
29432943 break;
29442944 case NodeTypeBoolLiteral:
test/compile_errors.zig+1-1
......@@ -234,7 +234,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
234234
235235 cases.add(
236236 "usingnamespace with wrong type",
237 \\use void;
237 \\usingnamespace void;
238238 ,
239239 "tmp.zig:1:1: error: expected struct, enum, or union; found 'void'",
240240 );
test/stage1/behavior.zig+1
......@@ -93,6 +93,7 @@ comptime {
9393 _ = @import("behavior/undefined.zig");
9494 _ = @import("behavior/underscore.zig");
9595 _ = @import("behavior/union.zig");
96 _ = @import("behavior/usingnamespace.zig");
9697 _ = @import("behavior/var_args.zig");
9798 _ = @import("behavior/vector.zig");
9899 _ = @import("behavior/void.zig");
test/stage1/behavior/usingnamespace.zig created+14
......@@ -0,0 +1,14 @@
1const std = @import("std");
2
3fn Foo(comptime T: type) type {
4 return struct {
5 usingnamespace T;
6 };
7}
8
9test "usingnamespace inside a generic struct" {
10 const std2 = Foo(std);
11 const testing2 = Foo(std.testing);
12 std2.testing.expect(true);
13 testing2.expect(true);
14}