From 7ec00e4f40af19de2bd3e2d814d618cf7e6a2376 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 1 Nov 2024 13:13:27 -0700 Subject: [PATCH] Allow member/member_frame also in freestanding methods with :: This is currently limited to classes without subclasses --- dev/src/lobster/idents.h | 3 ++- dev/src/lobster/parser.h | 16 ++++++++++++++-- tests/misc/frame.lobster | 10 +++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/dev/src/lobster/idents.h b/dev/src/lobster/idents.h index 0d676dc5b..5a8e6b9ce 100644 --- a/dev/src/lobster/idents.h +++ b/dev/src/lobster/idents.h @@ -1275,7 +1275,8 @@ struct SymbolTable { udt.ssuperclass = supertype->udt; } PushSuperGenerics(udt.ssuperclass); - for (auto &field : udt.g.fields) { + for (size_t i = udt.sfields.size(); i < udt.g.fields.size(); i++) { + auto &field = udt.g.fields[i]; udt.sfields.push_back({ ResolveTypeVars(field.giventype, errl) }); } PopSuperGenerics(udt.ssuperclass); diff --git a/dev/src/lobster/parser.h b/dev/src/lobster/parser.h index aea7dd04d..5997dc1fc 100644 --- a/dev/src/lobster/parser.h +++ b/dev/src/lobster/parser.h @@ -389,6 +389,11 @@ struct Parser { // This is an arbitrary restriction that we could lift, just doesn't seem // great to have invisble extra members in structs. if (gudt->is_struct) Error("member declaration only allowed in classes"); + // TODO: This is not great: when "member" is used in an inline method decl, this should + // never happen, and it can later still be subclassed, but when it is used outside + // in a free-standing method we can't allow new fields to be added when a subclass + // has already copied them. We can maybe lift this restriction. + if (gudt->has_subclasses) Error("member cannot be added in freestanding method to class that has been subclassed"); st.bound_typevars_stack.push_back(gudt->generics); auto field_idx = gudt->fields.size(); ParseField(gudt, true, true); @@ -411,6 +416,10 @@ struct Parser { member->field_idx = field_idx; member->frame = frame; member->this_sid = this_sid; + for (UDT *udt = gudt->first; udt; udt = udt->next) { + // New fields have been added possibly non-inline, run this again to be sure. + st.ResolveFields(*udt, lex); + } list->Add(member); break; } @@ -531,7 +540,6 @@ struct Parser { GUDT *gudt = st.LookupStruct(sname); bool was_predeclaration = gudt && gudt->predeclaration; gudt = &st.StructDecl(sname, is_struct, lex); - gudtstack.push_back(gudt); UDT *udt = nullptr; if (Either(T_COLON, T_LT)) { // A regular struct declaration @@ -675,7 +683,6 @@ struct Parser { parent_list->Add(new UDTRef(line, udt)); } parent_list->Add(new GUDTRef(line, gudt, gudt->predeclaration)); - gudtstack.pop_back(); } FunRef *ParseNamedFunctionDefinition(bool is_constructor, bool isprivate, GUDT *self) { @@ -761,8 +768,10 @@ struct Parser { st.bound_typevars_stack.push_back(sf->generics); if (parens) Expect(T_LEFTPAREN); size_t nargs = 0; + bool self_withtype = false; if (self) { nargs++; + self_withtype = true; auto id = st.LookupDef("this", false, true); auto &arg = sf->args.back(); arg.type = &self->unspecialized_type; @@ -787,6 +796,7 @@ struct Parser { if (nargs == 1 && (arg.type->t == V_UUDT || IsUDT(arg.type->t))) { non_inline_method = true; self = GetGUDTAny(arg.type); + self_withtype = withtype; st.bound_typevars_stack.push_back(self->generics); } sf->giventypes.push_back({ arg.type }); @@ -885,6 +895,7 @@ struct Parser { } else { f.anonymous = true; } + if (self_withtype) gudtstack.push_back(self); // Parse the body. Line line = lex; if (!f.istype) { @@ -893,6 +904,7 @@ struct Parser { ParseBody(block, -1); ImplicitReturn(*ov); } + if (self_withtype) gudtstack.pop_back(); if (name) functionstack.pop_back(); if (non_inline_method) st.bound_typevars_stack.pop_back(); st.bound_typevars_stack.pop_back(); diff --git a/tests/misc/frame.lobster b/tests/misc/frame.lobster index c0a4eedea..0356fc76a 100644 --- a/tests/misc/frame.lobster +++ b/tests/misc/frame.lobster @@ -23,12 +23,19 @@ class C: member_frame a = 1 member_frame b = float2_1 member_frame s = "s" - member_frame r = D {} + def nested(): + member_frame rf = D {} + return rf + let r = nested() print "c: {a++} {b} {s} {r}" b += 1.0 s += "s" r.i++ +def freestanding(c::C): + member_frame a2 = 1 + print "a2: {a2++}" + def aa(): static_frame a = 1 static_frame b = float2_1 @@ -46,5 +53,6 @@ while gl.frame(): if count % 4: aa() c.f() + c.freestanding() if count++ == 10: return