// Given declarations d1 and d2, a declaration error occurs when: // // - d2 changes the meaning of the name declared by d1, or if not that, then // - d1 and d2 are both objects, or // - d1 and d2 are functions that cannot be overloaded, or // - d1 and d2 are types having different kinds. // // Note that d1 precedes d2 in lexical order. // // TODO: Would it make sense to poison the declaration so that it's not // analyzed in subsequent passes? We could essentially replace the existing // overload set with one containing a poisoned declaration. Any expression // that uses that name would have an invalid type. We could then use this // to list the places where the error affects use. void check_declarations(Context& cxt, Decl const& d1, Decl const& d2) { struct fn { Context& cxt; Decl const& d2; void operator()(Decl const& d) { lingo_unhandled(d); } void operator()(Object_decl const& d1) { return check_declarations(cxt, d1, cast_as(d1, d2)); } void operator()(Function_decl const& d1) { return check_declarations(cxt, d1, cast_as(d1, d2)); } void operator()(Type_decl const& d1) { return check_declarations(cxt, d1, cast_as(d1, d2)); } }; if (typeid(d1) != typeid(d2)) { // TODO: Get the source location right. error(cxt, "declaration changes the meaning of '{}'", d1.name()); note("'{}' previously declared as:", d1.name()); // TODO: Don't print the definition. It's not germaine to // the error. If we have source locations, I wonder if we // can just point at the line. note("{}", d1); throw Declaration_error(); } apply(d1, fn{cxt, d2}); }
void check_declarations(Context& cxt, Object_decl const& d1, Object_decl const& d2) { struct fn { char const* operator()(Decl const& d) { lingo_unhandled(d); } char const* operator()(Variable_decl const& d) { return "variable"; } char const* operator()(Field_decl const& d) { return "member variable"; } char const* operator()(Object_parm const& d) { return "parameter"; } }; error(cxt, "redeclaration of {} with the same name", apply(d1, fn{})); throw Declaration_error(); }
void check_declarations(Context& cxt, Type_decl const& d1, Type_decl const& d2) { Type const& t1 = d1.type(); Type const& t2 = d2.type(); if (is_different(t1, t2)) { // TODO: Get the source location right. error(cxt, "declaration of '{}' as a different kind of type", d1.name()); note("'{}' previously declared as:", d1.name()); // TODO: Don't print the definition. It's not germaine to // the error. If we have source locations, I wonder if we // can just point at the line. note("{}", d1); throw Declaration_error(); } }
// FIXME: Verify this diagnostics. void check_declarations(Context& cxt, Type_decl const& d1, Type_decl const& d2) { error(cxt, "declaration of '{}' as a different kind of type", d1.name()); throw Declaration_error(); }