From b9f56afb68fa2538521a21162e5a73392d74ae80 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 12 Nov 2023 23:12:46 -0800 Subject: [PATCH] Remove Decl::s. This was a temporary hack to make symbol refactoring possible. We can remove it now. Every Decl that creates a symbol can cache it privately. Unfortunately, SymbolExpr makes recovering sym() fairly difficult. For now make it a virtual function, however, SymbolExpr will likely go away when we unify semantic pipeline. --- compiler/array-helpers.cpp | 51 ++++++----- compiler/assembler.cpp | 33 ++++--- compiler/code-generator.cpp | 38 +++++--- compiler/expressions.cpp | 12 +-- compiler/messages.h | 1 + compiler/name-resolution.cpp | 70 +++++++-------- compiler/parse-node.h | 61 ++++++++----- compiler/semantics.cpp | 87 ++++++++++++------- compiler/symbols.cpp | 29 ++++--- compiler/symbols.h | 2 +- tests/basic/view-as-to-array-2.sp | 6 +- .../fail-bad-scope-resolution-2.sp | 10 +++ .../fail-bad-scope-resolution-2.txt | 1 + 13 files changed, 234 insertions(+), 167 deletions(-) create mode 100644 tests/compile-only/fail-bad-scope-resolution-2.sp create mode 100644 tests/compile-only/fail-bad-scope-resolution-2.txt diff --git a/compiler/array-helpers.cpp b/compiler/array-helpers.cpp index f9f6f595f..73b45ed08 100644 --- a/compiler/array-helpers.cpp +++ b/compiler/array-helpers.cpp @@ -327,9 +327,7 @@ ArraySizeResolver::ResolveDimExprs() return true; } -bool -ArraySizeResolver::ResolveDimExpr(Expr* expr, value* v) -{ +bool ArraySizeResolver::ResolveDimExpr(Expr* expr, value* v) { auto& sc = *sema_->context(); if (!expr->Bind(sc)) return false; @@ -340,12 +338,13 @@ ArraySizeResolver::ResolveDimExpr(Expr* expr, value* v) // int blah[X]; // // For backward compatibility with a huge number of plugins. - auto sym = sym_expr->sym(); - auto type = types_->find(sym->tag); - if (sym->decl->as() && !type->asEnumStruct() && sym->ident == iCONSTEXPR) { - *v = {}; - v->set_constval(sym->addr()); - return true; + auto decl = sym_expr->decl(); + if (auto ed = decl->as()) { + if (ed->sym()) { + *v = {}; + v->set_constval(ed->array_size()); + return true; + } } } @@ -491,16 +490,22 @@ CalcArraySize(symbol* sym) return size; } -bool -FixedArrayValidator::CheckArgument(Expr* init) -{ +bool FixedArrayValidator::CheckArgument(Expr* init) { // As a special exception, array arguments can be initialized with a global // reference. SymbolExpr* expr = init->as(); if (!expr) return ValidateRank(0, init); - symbol* sym = expr->sym(); + Decl* decl = expr->decl(); + if (!decl) + return false; + + VarDecl* var = decl->as(); + if (!var) + return false; + + symbol* sym = var->sym(); if (!sym) { // This failed to bind, and we're still in the binding phase, so just // return false. @@ -700,12 +705,12 @@ FixedArrayValidator::ValidateEnumStruct(Expr* init) return false; } - symbol* field = (*field_iter)->s; + auto field = (*field_iter); // Advance early so we can use |continue|. field_iter++; - typeinfo_t type = TypeInfoFromSymbol(field); + const auto& type = field->type(); if (type.ident == iARRAY) { if (!CheckArrayInitialization(sema_, type, expr)) continue; @@ -721,7 +726,7 @@ FixedArrayValidator::ValidateEnumStruct(Expr* init) continue; } - matchtag(field->tag, v.tag, MATCHTAG_COERCE | MATCHTAG_ENUM_ASSN); + matchtag(type.tag(), v.tag, MATCHTAG_COERCE | MATCHTAG_ENUM_ASSN); } } @@ -892,7 +897,7 @@ class ArrayEmitter final cell Emit(int rank, Expr* expr); size_t AddString(StringExpr* expr); - void AddInlineArray(symbol* field, ArrayExpr* expr); + void AddInlineArray(LayoutFieldDecl* field, ArrayExpr* expr); void EmitPadding(size_t rank_size, int tag, size_t emitted, bool ellipses, const ke::Maybe prev1, const ke::Maybe prev2); @@ -971,15 +976,15 @@ ArrayEmitter::Emit(int rank, Expr* init) size_t emitted = AddString(expr); - symbol* field = (*field_iter)->s; + auto field = (*field_iter); assert(field); - EmitPadding(field->dim(0), field->tag, emitted, false, {}, {}); + EmitPadding(field->type().dim[0], field->type().tag(), emitted, false, {}, {}); } else if (ArrayExpr* expr = item->as()) { // Subarrays can only appear in an enum struct. Normal 2D cases // would flow through the check at the start of this function. assert(es_); - symbol* field = (*field_iter)->s; + auto field = (*field_iter); AddInlineArray(field, expr); } else { assert(item->val().ident == iCONSTEXPR); @@ -1007,9 +1012,7 @@ ArrayEmitter::Emit(int rank, Expr* init) return (start * sizeof(cell)) | kDataFlag; } -void -ArrayEmitter::AddInlineArray(symbol* field, ArrayExpr* array) -{ +void ArrayEmitter::AddInlineArray(LayoutFieldDecl* field, ArrayExpr* array) { ke::Maybe prev1, prev2; for (const auto& item : array->exprs()) { @@ -1019,7 +1022,7 @@ ArrayEmitter::AddInlineArray(symbol* field, ArrayExpr* array) prev1 = ke::Some(item->val().constval()); } - EmitPadding(field->dim(0), field->tag, array->exprs().size(), + EmitPadding(field->type().dim[0], field->type().tag(), array->exprs().size(), array->ellipses(), prev1, prev2); } diff --git a/compiler/assembler.cpp b/compiler/assembler.cpp index 8ada7ee39..dc97f074e 100644 --- a/compiler/assembler.cpp +++ b/compiler/assembler.cpp @@ -142,7 +142,7 @@ class RttiBuilder void encode_signature_into(std::vector& bytes, functag_t* ft); void encode_enum_into(std::vector& bytes, Type* type); void encode_tag_into(std::vector& bytes, int tag); - void encode_ret_array_into(std::vector& bytes, symbol* sym); + void encode_ret_array_into(std::vector& bytes, const typeinfo_t& type); void encode_funcenum_into(std::vector& bytes, Type* type, funcenum_t* fe); void encode_var_type(std::vector& bytes, const variable_type_t& info); void encode_struct_into(std::vector& bytes, Type* type); @@ -447,7 +447,7 @@ RttiBuilder::add_enumstruct(Type* type) smx_rtti_enumstruct es = {}; es.name = names_->add(*cc_.atoms(), type->name()); es.first_field = es_fields_->count(); - es.size = es_decl->s->addr(); + es.size = es_decl->sym()->addr(); enumstructs_->add(es); // Pre-allocate storage in case of nested types. @@ -458,21 +458,20 @@ RttiBuilder::add_enumstruct(Type* type) // Add all fields. size_t index = 0; for (auto iter = enumlist.begin(); iter != enumlist.end(); iter++) { - auto field_decl = (*iter); - auto field = field_decl->s; + auto field = (*iter); int dims[1], dimcount = 0; - if (field->dim_count()) - dims[dimcount++] = field->dim(0); + if (field->type().numdim()) + dims[dimcount++] = field->type().dim[0]; - variable_type_t type = {field->semantic_tag, dims, dimcount, false}; + variable_type_t type = {field->type().semantic_tag(), dims, dimcount, false}; std::vector encoding; encode_var_type(encoding, type); smx_rtti_es_field info; - info.name = names_->add(field_decl->name()); + info.name = names_->add(field->name()); info.type_id = to_typeid(encoding); - info.offset = field->addr(); + info.offset = field->offset(); es_fields_->at(es.first_field + index) = info; index++; } @@ -539,7 +538,7 @@ RttiBuilder::to_typeid(const std::vector& bytes) uint32_t RttiBuilder::encode_signature(FunctionDecl* fun) { assert(fun == fun->canonical()); - auto sym = fun->s; + auto sym = fun->sym(); std::vector bytes; @@ -552,8 +551,8 @@ uint32_t RttiBuilder::encode_signature(FunctionDecl* fun) { bytes.push_back(cb::kVariadic); VarDecl* child = fun->return_array() ? fun->return_array()->var : nullptr; - if (child && child->s->dim_count()) { - encode_ret_array_into(bytes, child->s); + if (child && child->type().numdim()) { + encode_ret_array_into(bytes, child->type()); } else if (sym->tag == types_->tag_void()) { bytes.push_back(cb::kVoid); } else { @@ -668,14 +667,12 @@ RttiBuilder::encode_enumstruct_into(std::vector& bytes, Type* type) CompactEncodeUint32(bytes, add_enumstruct(type)); } -void -RttiBuilder::encode_ret_array_into(std::vector& bytes, symbol* sym) -{ - for (int i = 0; i < sym->dim_count(); i++) { +void RttiBuilder::encode_ret_array_into(std::vector& bytes, const typeinfo_t& type) { + for (int i = 0; i < type.numdim(); i++) { bytes.push_back(cb::kFixedArray); - CompactEncodeUint32(bytes, sym->dim(i)); + CompactEncodeUint32(bytes, type.dim[i]); } - encode_tag_into(bytes, sym->tag); + encode_tag_into(bytes, type.tag()); } uint8_t diff --git a/compiler/code-generator.cpp b/compiler/code-generator.cpp index 1d35f651c..2054ffa7b 100644 --- a/compiler/code-generator.cpp +++ b/compiler/code-generator.cpp @@ -454,7 +454,7 @@ CodeGenerator::EmitPstruct(VarDeclBase* decl) } else if (auto expr = field->value->as()) { values[arg->index] = expr->value(); } else if (auto expr = field->value->as()) { - values[arg->index] = expr->sym()->addr(); + values[arg->index] = expr->decl()->sym()->addr(); } else { assert(false); } @@ -516,8 +516,8 @@ CodeGenerator::EmitExpr(Expr* expr) } case ExprKind::ThisExpr: { auto e = expr->to(); - if (e->sym()->ident == iREFARRAY) - __ address(e->sym(), sPRI); + if (e->decl()->sym()->ident == iREFARRAY) + __ address(e->decl()->sym(), sPRI); break; } case ExprKind::StringExpr: { @@ -1075,7 +1075,7 @@ CodeGenerator::EmitTernaryExpr(TernaryExpr* expr) void CodeGenerator::EmitSymbolExpr(SymbolExpr* expr) { - symbol* sym = expr->sym(); + symbol* sym = expr->decl()->sym(); switch (sym->ident) { case iARRAY: case iREFARRAY: @@ -1161,9 +1161,15 @@ CodeGenerator::EmitFieldAccessExpr(FieldAccessExpr* expr) // reserved for RvalueExpr(). EmitExpr(expr->base()); - if (expr->resolved() && expr->resolved()->s->addr()) { - __ const_alt(expr->resolved()->s->addr() << 2); - __ emit(OP_ADD); + // Only enum struct accesses have a resolved decl. + if (!expr->resolved()) + return; + + if (LayoutFieldDecl* field = expr->resolved()->as()) { + if (field->offset()) { + __ const_alt(field->offset() << 2); + __ emit(OP_ADD); + } } } @@ -1311,7 +1317,7 @@ CodeGenerator::EmitNewArrayExpr(NewArrayExpr* expr) // that when synthesizing a NewArrayExpr for old-style declarations, // it is impossible to have an enum struct. // :TODO: test this - __ emit(OP_PUSH_C, es->s->addr()); + __ emit(OP_PUSH_C, es->array_size()); numdim++; } @@ -1351,7 +1357,7 @@ CodeGenerator::EmitReturnArrayStmt(ReturnStmt* stmt) auto info = fun_->return_array(); if (array.iv.empty()) { VarDecl* sub_decl = info->var; - symbol* sub = sub_decl->s; + symbol* sub = sub_decl->sym(); // A much simpler copy can be emitted. __ load_hidden_arg(fun_, sub, true); @@ -1391,7 +1397,7 @@ CodeGenerator::EmitReturnArrayStmt(ReturnStmt* stmt) // add.c ; address to data // memcopy __ emit(OP_PUSH_PRI); - __ load_hidden_arg(fun_, info->var->s, false); + __ load_hidden_arg(fun_, info->var->sym(), false); __ emit(OP_INITARRAY_ALT, dat_addr, iv_size, 0, 0, 0); __ emit(OP_MOVE_PRI); __ emit(OP_ADD_C, iv_size * sizeof(cell)); @@ -2189,9 +2195,17 @@ int CodeGenerator::DynamicMemorySize() const { } void CodeGenerator::EnqueueDebugSymbol(Decl* decl, uint32_t pc) { - if (decl->s->vclass == sGLOBAL) { + int vclass = 0; + if (auto fun = decl->as()) + vclass = fun->is_static() ? sSTATIC : sGLOBAL; + else if (auto var = decl->as()) + vclass = var->vclass(); + else + assert(false); + + if (vclass == sGLOBAL) { global_syms_.emplace_back(decl, pc); - } else if (decl->s->vclass == sSTATIC && !func_) { + } else if (vclass == sSTATIC && !func_) { static_syms_.back().second.emplace_back(decl, pc); } else { local_syms_.back().emplace_back(decl, pc); diff --git a/compiler/expressions.cpp b/compiler/expressions.cpp index 6870df365..50d74c29c 100644 --- a/compiler/expressions.cpp +++ b/compiler/expressions.cpp @@ -150,7 +150,7 @@ find_userop(SemaContext& sc, int oper, int tag1, int tag2, int numparam, const v if (!chain) return false; - symbol* sym = nullptr; + FunctionDecl* decl = nullptr; bool swapparams; bool is_commutative = commutative(oper); for (auto iter = chain; iter; iter = iter->next) { @@ -166,13 +166,13 @@ find_userop(SemaContext& sc, int oper, int tag1, int tag2, int numparam, const v swapped = true; } if (matched) { - sym = iter->s; + decl = fun; swapparams = swapped; break; } } - if (!sym) + if (!decl) return false; /* we don't want to use the redefined operator in the function that @@ -181,13 +181,13 @@ find_userop(SemaContext& sc, int oper, int tag1, int tag2, int numparam, const v * fixed:operator+(fixed:a, fixed:b) * return a + b */ - if (sym == sc.func()) { + if (decl == sc.func_node()) { report(408); } - markusage(sym, uREAD); + markusage(decl, uREAD); - op->sym = sym; + op->sym = decl->sym(); op->oper = oper; op->paramspassed = (oper == 0) ? 1 : numparam; op->savepri = savepri; diff --git a/compiler/messages.h b/compiler/messages.h index 0ebf37775..f825f3415 100644 --- a/compiler/messages.h +++ b/compiler/messages.h @@ -326,4 +326,5 @@ static const char* errmsg_ex[] = { /*442*/ "method aliases are no longer supported\n", /*443*/ "enum %s already has a methodmap\n", /*444*/ "cannot find method \"%s.%s\"\n", + /*445*/ "%s must be a field\n", }; diff --git a/compiler/name-resolution.cpp b/compiler/name-resolution.cpp index 057625890..e05c70c1a 100644 --- a/compiler/name-resolution.cpp +++ b/compiler/name-resolution.cpp @@ -86,7 +86,7 @@ SemaContext::BindType(const token_pos_t& pos, typeinfo_t* ti) ti->set_tag(0); ti->declared_tag = tag; - ti->dim.emplace_back(enum_type->s->addr()); + ti->dim.emplace_back(enum_type->array_size()); if (ti->ident != iARRAY && ti->ident != iREFARRAY) { ti->ident = iARRAY; @@ -159,9 +159,7 @@ BlockStmt::Bind(SemaContext& sc) return StmtList::Bind(sc); } -bool -EnumDecl::EnterNames(SemaContext& sc) -{ +bool EnumDecl::EnterNames(SemaContext& sc) { AutoErrorPos error_pos(pos_); int tag = 0; @@ -202,8 +200,8 @@ EnumDecl::EnterNames(SemaContext& sc) if (auto decl = FindSymbol(sc, name_)) { // If we were previously defined as a methodmap, don't overwrite the // symbol. Otherwise, flow into DefineConstant where we will error. - if (decl->s->ident == iMETHODMAP) - enumsym = decl->s; + if (auto mm = decl->as()) + enumsym = mm->sym(); } } @@ -238,11 +236,16 @@ EnumDecl::EnterNames(SemaContext& sc) value += increment_; else value *= increment_ * multiplier_; + field->set_sym(sym); } // set the enum name to the "next" value (typically the last value plus one) - if (enumsym) + if (enumsym) { enumsym->setAddr(value); + array_size_ = value; + } + + sym_ = enumsym; return true; } @@ -524,22 +527,21 @@ SymbolExpr::DoBind(SemaContext& sc, bool is_lval) if (auto fun = decl_->as()) decl_ = fun->canonical(); - if (!is_lval) - markusage(sym(), uREAD); + if (decl_ && !is_lval) + markusage(decl_, uREAD); return true; } -bool -ThisExpr::Bind(SemaContext& sc) -{ +bool ThisExpr::Bind(SemaContext& sc) { AutoErrorPos aep(pos_); - auto decl = FindSymbol(sc, sc.cc().atom("this")); - if (!decl) { + if (auto decl = FindSymbol(sc, sc.cc().atom("this"))) + decl_ = decl->as(); + + if (!decl_) { error(pos_, 166); return false; } - sym_ = decl->s; return true; } @@ -584,13 +586,12 @@ ArrayExpr::Bind(SemaContext& sc) bool SizeofExpr::Bind(SemaContext& sc) { AutoErrorPos aep(pos_); - auto decl = FindSymbol(sc, ident_); - if (!decl) { + decl_ = FindSymbol(sc, ident_); + if (!decl_) { report(pos_, 17) << ident_; return false; } - sym_ = decl->s; - markusage(sym_, uREAD); + markusage(decl_, uREAD); return true; } @@ -663,9 +664,11 @@ ReturnStmt::Bind(SemaContext& sc) // Do some peeking to see if this really returns an array. This is a // compatibility hack. if (auto sym_expr = expr_->as()) { - if (auto sym = sym_expr->sym()) { - if (sym->ident == iARRAY || sym->ident == iREFARRAY) - sc.func_node()->set_maybe_returns_array(); + if (auto decl = sym_expr->decl()) { + if (auto var = decl->as()) { + if (var->type().ident == iARRAY || var->type().ident == iREFARRAY) + sc.func_node()->set_maybe_returns_array(); + } } } @@ -738,7 +741,7 @@ bool FunctionDecl::EnterNames(SemaContext& sc) { } if (other) { - sym_ = other->s; + sym_ = other->sym(); proto_or_impl_ = other; other->proto_or_impl_ = this; } else { @@ -747,10 +750,6 @@ bool FunctionDecl::EnterNames(SemaContext& sc) { DefineSymbol(sc, this, scope); } - - if (!s) - s = sym_; - return true; } @@ -792,17 +791,13 @@ FunctionDecl* FunctionDecl::CanRedefine(Decl* other_decl) { return nullptr; } -bool -FunctionDecl::Bind(SemaContext& outer_sc) -{ +bool FunctionDecl::Bind(SemaContext& outer_sc) { if (!outer_sc.BindType(pos_, &decl_.type)) return false; // Only named functions get an early symbol in EnterNames. if (!sym_) sym_ = new symbol(this, 0, iFUNCTN, sGLOBAL, 0); - if (!s) - s = sym_; // The forward's prototype is canonical. If this symbol has a forward, we // don't set or override the return type when we see the public @@ -821,7 +816,7 @@ FunctionDecl::Bind(SemaContext& outer_sc) typeinfo.set_tag(0); typeinfo.ident = iREFARRAY; typeinfo.declared_tag = *this_tag_; - typeinfo.dim.emplace_back(enum_type->s->addr()); + typeinfo.dim.emplace_back(enum_type->array_size()); } else { typeinfo.set_tag(*this_tag_); typeinfo.ident = iVARIABLE; @@ -1110,12 +1105,15 @@ EnumStructDecl::EnterNames(SemaContext& sc) } seen.emplace(field->name()); + field->set_offset(position); + symbol* child = new symbol(field, position, field->type().ident, sGLOBAL, field->type().semantic_tag()); if (field->type().numdim()) { child->set_dim_count(1); child->set_dim(0, field->type().dim[0]); } + field->set_sym(child); cell size = 1; if (field->type().numdim()) { @@ -1141,6 +1139,7 @@ EnumStructDecl::EnterNames(SemaContext& sc) } root_->setAddr(position); + array_size_ = position; return errors.ok(); } @@ -1195,10 +1194,7 @@ bool MethodmapDecl::EnterNames(SemaContext& sc) { return false; } - assert(ed->s->ident == iCONSTEXPR); - assert(tag_ == ed->s->tag); - - sym_ = ed->s; + sym_ = ed->sym(); sym_->ident = iMETHODMAP; ed->set_mm(this); } else { diff --git a/compiler/parse-node.h b/compiler/parse-node.h index 34afc9b2b..f8178ce4a 100644 --- a/compiler/parse-node.h +++ b/compiler/parse-node.h @@ -288,9 +288,9 @@ class Decl : public Stmt name_(name) {} - Atom* name() const { - return name_; - } + virtual symbol* sym() const { return nullptr; } + + Atom* name() const { return name_; } protected: Atom* DecorateInnerName(Atom* parent_name, Atom* field_name); @@ -301,8 +301,6 @@ class Decl : public Stmt public: // :TODO: remove. Decl* next = nullptr; - // :TODO: remove - symbol* s = nullptr; }; class BinaryExpr; @@ -325,32 +323,30 @@ class VarDeclBase : public Decl BinaryExpr* init() const { return init_; } Expr* init_rhs() const; - int vclass() const { - return vclass_; - } - const typeinfo_t& type() const { - return type_; - } - typeinfo_t* mutable_type() { - return &type_; - } + int vclass() const { return vclass_; } + const typeinfo_t& type() const { return type_; } + typeinfo_t* mutable_type() { return &type_; } void set_init(Expr* expr); bool autozero() const { return autozero_; } void set_no_autozero() { autozero_ = false; } - symbol* sym() const { return sym_; } bool is_public() const { return is_public_; } bool is_stock() const { return is_stock_; } bool is_read() const { return is_read_; } void set_is_read() { is_read_ = true; } bool is_written() const { return is_written_; } void set_is_written() { is_written_ = true; } + symbol* sym() const override { return sym_; } + void set_sym(symbol* sym) { + assert(!sym_); + sym_ = sym; + } bool is_used() const { return is_read_ || is_written_; } protected: typeinfo_t type_; - int vclass_; // This will be implied by scope, when we get there. BinaryExpr* init_ = nullptr; + uint8_t vclass_; // This will be implied by scope, when we get there. bool is_public_ : 1; bool is_static_ : 1; bool is_stock_ : 1; @@ -419,9 +415,12 @@ class EnumFieldDecl : public Decl static bool is_a(Stmt* node) { return node->kind() == StmtKind::EnumFieldDecl; } Expr* value() const { return value_; } + symbol* sym() const override { return sym_; } + void set_sym(symbol* sym) { sym_ = sym; } private: Expr* value_; + symbol* sym_ = nullptr; }; class EnumDecl : public Decl @@ -447,6 +446,8 @@ class EnumDecl : public Decl PoolArray& fields() { return fields_; } int increment() const { return increment_; } int multiplier() const { return multiplier_; } + symbol* sym() const override { return sym_; } + int array_size() const { return array_size_; } MethodmapDecl* mm() const { return mm_; } void set_mm(MethodmapDecl* mm) { mm_ = mm; } @@ -457,7 +458,9 @@ class EnumDecl : public Decl PoolArray fields_; int increment_; int multiplier_; + int array_size_ = 0; MethodmapDecl* mm_; + symbol* sym_ = nullptr; }; struct StructField { @@ -871,14 +874,14 @@ class SizeofExpr final : public Expr Atom* field() const { return field_; } int suffix_token() const { return suffix_token_; } int array_levels() const { return array_levels_; } - symbol* sym() const { return sym_; } + Decl* decl() const { return decl_; } private: Atom* ident_; Atom* field_; int suffix_token_; int array_levels_; - symbol* sym_ = nullptr; + Decl* decl_ = nullptr; }; class SymbolExpr final : public Expr @@ -899,7 +902,6 @@ class SymbolExpr final : public Expr static bool is_a(Expr* node) { return node->kind() == ExprKind::SymbolExpr; } Decl* decl() const { return decl_; } - symbol* sym() const { return decl_ ? decl_->s : nullptr; } private: bool DoBind(SemaContext& sc, bool is_lval); @@ -1106,8 +1108,7 @@ class ThisExpr final : public Expr { public: explicit ThisExpr(const token_pos_t& pos) - : Expr(ExprKind::ThisExpr, pos), - sym_(nullptr) + : Expr(ExprKind::ThisExpr, pos) {} bool Bind(SemaContext& sc) override; @@ -1115,10 +1116,10 @@ class ThisExpr final : public Expr static bool is_a(Expr* node) { return node->kind() == ExprKind::ThisExpr; } - symbol* sym() const { return sym_; } + VarDeclBase* decl() const { return decl_; } private: - symbol* sym_; + VarDeclBase* decl_ = nullptr; }; class NullExpr final : public Expr @@ -1628,7 +1629,7 @@ class FunctionDecl : public Decl declinfo_t& decl() { return decl_; } const declinfo_t& decl() const { return decl_; } - symbol* sym() const { return sym_; } + symbol* sym() const override { return sym_; } void set_sym(symbol* sym) { sym_ = sym; } const typeinfo_t& type() const { return decl_.type; } @@ -1787,8 +1788,15 @@ class LayoutFieldDecl : public Decl const typeinfo_t& type() const { return type_; } typeinfo_t& mutable_type() { return type_; } + cell_t offset() const { return offset_; } + void set_offset(cell_t offset) { offset_ = offset; } + symbol* sym() const override { return sym_; } + void set_sym(symbol* sym) { sym_ = sym; } + private: typeinfo_t type_; + cell_t offset_; + symbol* sym_ = nullptr; }; class EnumStructDecl : public LayoutDecl @@ -1807,10 +1815,14 @@ class EnumStructDecl : public LayoutDecl PoolArray& methods() { return methods_; } PoolArray& fields() { return fields_; } + symbol* sym() const override { return root_; } + cell_t array_size() const { return array_size_; } + private: PoolArray methods_; PoolArray fields_; symbol* root_ = nullptr; + cell_t array_size_ = 0; }; class MethodmapPropertyDecl : public Decl { @@ -1871,6 +1883,7 @@ class MethodmapDecl : public LayoutDecl int tag() const { return tag_; } MethodmapMethodDecl* ctor() const { return ctor_; } MethodmapMethodDecl* dtor() const { return dtor_; } + symbol* sym() const override { return sym_; } private: bool BindGetter(SemaContext& sc, MethodmapPropertyDecl* prop); diff --git a/compiler/semantics.cpp b/compiler/semantics.cpp index 4e5ef0b75..d313a248d 100644 --- a/compiler/semantics.cpp +++ b/compiler/semantics.cpp @@ -278,7 +278,13 @@ bool Semantics::CheckPstructArg(VarDeclBase* decl, const pstruct_t* ps, matchtag(arg->type.tag(), expr->tag(), MATCHTAG_COERCE); } } else if (auto expr = field->value->as()) { - auto sym = expr->sym(); + auto var = expr->decl()->as(); + if (!var) { + report(expr->pos(), 405); + return false; + } + + auto sym = var->sym(); if (arg->type.ident == iVARIABLE) { if (sym->ident != iVARIABLE) { report(expr->pos(), 405); @@ -562,7 +568,7 @@ Expr* Semantics::AnalyzeForTest(Expr* expr) { report(expr, 205); } } else if (auto sym_expr = expr->as()) { - if (sym_expr->sym()->ident == iFUNCTN) + if (sym_expr->decl()->as()) report(expr, 249); } @@ -1271,7 +1277,7 @@ CastExpr::ProcessUses(SemaContext& sc) } void SymbolExpr::MarkUsed(SemaContext& sc) { - markusage(sym(), uREAD); + markusage(decl_, uREAD); } // This is a hack. Most code is not prepared to handle iMETHODMAP in type @@ -1288,7 +1294,7 @@ bool Semantics::CheckSymbolExpr(SymbolExpr* expr, bool allow_types) { return false; } - auto sym = expr->sym(); + auto sym = decl->sym(); auto& val = expr->val(); val.ident = sym->ident; val.sym = sym; @@ -1522,7 +1528,7 @@ IndexExpr::ProcessUses(SemaContext& sc) } bool Semantics::CheckThisExpr(ThisExpr* expr) { - auto sym = expr->sym(); + auto sym = expr->decl()->sym(); assert(sym->ident == iREFARRAY || sym->ident == iVARIABLE); auto& val = expr->val(); @@ -1773,31 +1779,34 @@ bool Semantics::CheckEnumStructFieldAccessExpr(FieldAccessExpr* expr, Type* type } auto& val = expr->val(); - if (field_decl->as()) { + if (auto fun = field_decl->as()) { if (!from_call) { report(expr, 76); return false; } val.ident = iFUNCTN; - val.sym = field_decl->s; + val.sym = fun->sym(); markusage(val.sym, uREAD); return true; } - auto field = field_decl->s; + auto field = field_decl->as(); + assert(field); + + int tag = field->type().semantic_tag(); typeinfo_t ti{}; - if (types_->find(field->tag)->isEnumStruct()) { + if (types_->find(tag)->isEnumStruct()) { val.tag = 0; - ti.declared_tag = field->tag; + ti.declared_tag = tag; } else { - val.tag = field->tag; + val.tag = tag; } ti.set_tag(val.tag); - if (field->dim_count()) { - ti.dim = {field->dim(0)}; + if (field->type().numdim()) { + ti.dim = {field->type().dim[0]}; ti.ident = iREFARRAY; } else { ti.ident = (ti.tag() == types_->tag_string()) ? iARRAYCHAR : iARRAYCELL; @@ -1807,7 +1816,7 @@ bool Semantics::CheckEnumStructFieldAccessExpr(FieldAccessExpr* expr, Type* type // Hack. Remove when we can. auto var = new VarDecl(expr->pos(), field_decl->name(), ti, base->val().sym->vclass, false, false, false, nullptr); - auto sym = new symbol(var, field->addr(), ti.ident, var->vclass(), ti.tag()); + auto sym = new symbol(var, field->offset(), ti.ident, var->vclass(), ti.tag()); if (ti.dim.size()) { sym->set_dim_count(ti.dim.size()); for (int i = 0; i < ti.dim.size(); i++) @@ -1834,11 +1843,17 @@ bool Semantics::CheckStaticFieldAccessExpr(FieldAccessExpr* expr) { Decl* field = FindEnumStructField(type, expr->name()); if (!field) { report(expr, 105) << type->name() << expr->name(); - return FALSE; + return false; + } + + auto fd = field->as(); + if (!fd) { + report(expr, 445) << field->name(); + return false; } auto& val = expr->val(); - val.set_constval(field->s->addr()); + val.set_constval(fd->offset()); val.tag = 0; return true; } @@ -1846,16 +1861,23 @@ bool Semantics::CheckStaticFieldAccessExpr(FieldAccessExpr* expr) { bool Semantics::CheckSizeofExpr(SizeofExpr* expr) { AutoErrorPos aep(expr->pos()); - symbol* sym = expr->sym(); + symbol* sym = nullptr; + if (auto var = expr->decl()->as()) + sym = var->sym(); + else if (auto ed = expr->decl()->as()) + sym = ed->sym(); + else if (auto esd = expr->decl()->as()) + sym = esd->sym(); + if (!sym) { + report(expr, 72); + return false; + } markusage(sym, uREAD); if (sym->ident == iCONSTEXPR) { report(expr, 39); // constant symbol has no size return false; - } else if (sym->ident == iFUNCTN) { - report(expr, 72); // "function" symbol has no size - return false; } auto& val = expr->val(); @@ -1889,13 +1911,18 @@ bool Semantics::CheckSizeofExpr(SizeofExpr* expr) { if (enum_type) { assert(enum_type->asEnumStruct()); - Decl* field = FindEnumStructField(enum_type, expr->field()); - if (!field) { + Decl* decl = FindEnumStructField(enum_type, expr->field()); + if (!decl) { report(expr, 105) << enum_type->name() << expr->field(); return false; } - if (field->s->dim_count()) { - val.set_constval(field->s->dim(0)); + auto field = decl->as(); + if (!field) { + report(expr, 445) << expr->field(); + return false; + } + if (field->type().numdim()) { + val.set_constval(field->type().dim[0]); return true; } return true; @@ -1983,7 +2010,7 @@ bool Semantics::CheckCallExpr(CallExpr* call) { val.tag = sym->tag; if (fun->return_array()) { val.ident = iREFARRAY; - val.sym = fun->return_array()->var->s; + val.sym = fun->return_array()->var->sym(); NeedsHeapAlloc(call); } @@ -2500,7 +2527,9 @@ bool Semantics::TestSymbol(symbol* sym, bool testconst) { bool Semantics::TestSymbols(SymbolScope* root, bool testconst) { bool entry = false; root->ForEachSymbol([&](Decl* decl) -> void { - entry |= TestSymbol(decl->s, testconst); + auto sym = decl->sym(); + if (sym) + entry |= TestSymbol(sym, testconst); }); return entry; } @@ -2606,7 +2635,6 @@ bool Semantics::CheckReturnStmt(ReturnStmt* stmt) { } /* see if this function already has a sub type (an array attached) */ auto sub = fun->return_array() ? fun->return_array()->var : nullptr; - assert(sub == nullptr || sub->s->ident == iREFARRAY); if (sc_->returns_value()) { int retarray = (v.ident == iARRAY || v.ident == iREFARRAY); /* there was an earlier "return" statement in this function */ @@ -2647,7 +2675,7 @@ bool Semantics::CheckArrayReturnStmt(ReturnStmt* stmt) { if (curfunc->return_array()) { VarDecl* sub_decl = curfunc->return_array()->var; - auto sub = sub_decl->s; + auto sub = sub_decl->sym(); assert(sub->ident == iREFARRAY); // this function has an array attached already; check that the current @@ -2700,6 +2728,7 @@ bool Semantics::CheckArrayReturnStmt(ReturnStmt* stmt) { sub = NewVariable(var, (argcount + 3) * sizeof(cell), iREFARRAY, sGLOBAL, curfunc->type().tag(), dim, array.numdim(), array.enum_struct_tag()); + var->set_sym(sub); auto info = new FunctionDecl::ReturnArrayInfo; info->var = var; @@ -3366,7 +3395,7 @@ void fill_arg_defvalue(CompileContext& cc, ArgDecl* decl) { def->tag = decl->type().tag(); if (auto expr = decl->init_rhs()->as()) { - symbol* sym = expr->sym(); + symbol* sym = expr->decl()->sym(); assert(sym->vclass == sGLOBAL); def->sym = sym; diff --git a/compiler/symbols.cpp b/compiler/symbols.cpp index cb5e52250..e5f93f8f0 100644 --- a/compiler/symbols.cpp +++ b/compiler/symbols.cpp @@ -40,12 +40,8 @@ void AddGlobal(CompileContext& cc, symbol* sym) scope->AddChain(sym->decl); } -void markusage(FunctionDecl* decl, int usage) { - markusage(decl->sym(), usage); -} - -void markusage(symbol* sym, int usage) { - if (auto var = sym->decl->as()) { +void markusage(Decl* decl, int usage) { + if (auto var = decl->as()) { if (usage & uREAD) var->set_is_read(); if (usage & uWRITTEN) @@ -61,6 +57,13 @@ void markusage(symbol* sym, int usage) { if (!parent_func) return; + auto fun = decl->as(); + if (!fun) + return; + fun = fun->canonical(); + + symbol* sym = fun->sym(); + // The reference graph only contains outgoing edges to global or file-static // variables. Locals and such are computed by TestSymbols and don't need // special handling, there's no concept of "stock" there. @@ -70,7 +73,11 @@ void markusage(symbol* sym, int usage) { return; assert(parent_func->canonical() == parent_func); - parent_func->AddReferenceTo(sym->decl->as()->canonical()); + parent_func->AddReferenceTo(decl->as()->canonical()); +} + +void markusage(symbol* sym, int usage) { + markusage(sym->decl, usage); } symbol::symbol(Decl* decl, cell symaddr, IdentifierKind symident, int symvclass, int symtag) @@ -85,8 +92,6 @@ symbol::symbol(Decl* decl, cell symaddr, IdentifierKind symident, int symvclass, { assert(ident != iINVALID); assert(decl); - assert(!decl->s); - decl->s = this; } void symbol::set_dim_count(int dim_count) { @@ -163,9 +168,7 @@ enum class NewNameStatus { Duplicated }; -static NewNameStatus -GetNewNameStatus(SemaContext& sc, Atom* name, int vclass) -{ +static NewNameStatus GetNewNameStatus(SemaContext& sc, Atom* name, int vclass) { SymbolScope* scope; Decl* decl = nullptr; if (sc.func_node() && sc.func_node()->is_native()) { @@ -185,7 +188,7 @@ GetNewNameStatus(SemaContext& sc, Atom* name, int vclass) } if (scope == current) return NewNameStatus::Duplicated; - if (current->kind() == sARGUMENT && decl->s->ident == iFUNCTN) + if (current->kind() == sARGUMENT && decl->as()) return NewNameStatus::Ok; return NewNameStatus::Shadowed; } diff --git a/compiler/symbols.h b/compiler/symbols.h index f84742092..da9a072f8 100644 --- a/compiler/symbols.h +++ b/compiler/symbols.h @@ -208,7 +208,7 @@ symbol* DefineConstant(SemaContext& sc, Decl* decl, const token_pos_t& pos, cell bool CheckNameRedefinition(SemaContext& sc, Atom* name, const token_pos_t& pos, int vclass); void markusage(symbol* sym, int usage); -void markusage(FunctionDecl* decl, int usage); +void markusage(Decl* decl, int usage); symbol* NewVariable(Decl* decl, cell addr, IdentifierKind ident, int vclass, int tag, int dim[], int numdim, int semantic_tag); Decl* FindEnumStructField(Type* type, Atom* name); diff --git a/tests/basic/view-as-to-array-2.sp b/tests/basic/view-as-to-array-2.sp index 413870616..7da9682ba 100644 --- a/tests/basic/view-as-to-array-2.sp +++ b/tests/basic/view-as-to-array-2.sp @@ -1,9 +1,9 @@ #include -enum Handle: {}; +enum FileHandle: {}; enum Crab: {}; -stock void WriteFile(Handle hndl, const int[] items, int num_items, int size) +stock void WriteFile(FileHandle hndl, const int[] items, int num_items, int size) { for (int i = 0; i < num_items; i++) { printnum(view_as(items[i])); @@ -14,7 +14,7 @@ stock void WriteFile(Handle hndl, const int[] items, int num_items, int size) public void main() { Crab test[3] = { Crab:1, Crab:2, Crab:3 }; float vec[3] = { 1.0, 2.0, 3.0 }; - Handle hFile; + FileHandle hFile; WriteFile(hFile, test, 3, 4); // warning: tag mismatch but works WriteFile(hFile, _:test, 3, 4); // All fine WriteFile(hFile, view_as(vec), 3, 4); diff --git a/tests/compile-only/fail-bad-scope-resolution-2.sp b/tests/compile-only/fail-bad-scope-resolution-2.sp new file mode 100644 index 000000000..2b0630dc4 --- /dev/null +++ b/tests/compile-only/fail-bad-scope-resolution-2.sp @@ -0,0 +1,10 @@ +enum struct Blah { + void F() { + } + + int a; +} + +public main() { + return Blah::F(); +} diff --git a/tests/compile-only/fail-bad-scope-resolution-2.txt b/tests/compile-only/fail-bad-scope-resolution-2.txt new file mode 100644 index 000000000..beecc2c26 --- /dev/null +++ b/tests/compile-only/fail-bad-scope-resolution-2.txt @@ -0,0 +1 @@ +(9) : error 445: Blah.F must be a field