Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/welder/annotations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,46 @@ struct no_reassign_spec {
}
};

// --- family_surface: opt a welded base into rod-synthesized family surfaces --

/** The stored form of a `family_surface` mark: the languages a welded BASE
class opts its family into a rod-synthesized version-agnostic surface for.

A *family* is two or more welded classes deriving one welded base — the
shape a versioned class template welded per instantiation makes. A rod that
implements family surfaces (the C# rod's dispatch members are the first)
may then hoist the member intersection the derived classes bind identically
onto the base, so base-typed code reads and writes data without naming a
concrete. Synthesizing members onto a base is too intrusive to infer from
structure alone, so it is strictly OPT-IN: a rod must synthesize nothing
for a base that does not carry this mark.

The mark goes on the BASE class (the entity that receives the synthesized
surface), not on the derived classes. welder core only stores and queries
it (@ref welder::family_surface_for); what a surface consists of is each
honoring rod's contract — a rod without the feature ignores the mark.

Usable bare (all languages) or called with languages to scope it, like
exclude_spec:
@code
[[=welder::mark::family_surface]] // every honoring rod
[[=welder::mark::family_surface(welder::lang::py)]] // one language only
@endcode
Repeated annotations union their languages.
*/
struct family_surface_spec {
unsigned mask = 0; /**< The languages to synthesize for; `0` == all languages. */

/** Scope the family surface to specific languages.
@tparam Ls the language enum types (deduced).
@param ls the languages to synthesize the surface for.
@return a scoped family_surface_spec. */
template <class... Ls>
consteval family_surface_spec operator()(Ls... ls) const {
return family_surface_spec{lang_mask(ls...)};
}
};

// --- trust_bindable: vouch that a type is representable outside welder's view --

/** The stored form of a `trust_bindable` member mark.
Expand Down Expand Up @@ -596,6 +636,7 @@ inline constexpr detail::include_spec include{}; /**< @see welder:
inline constexpr detail::only_spec only{}; /**< @see welder::detail::only_spec — must be called with ≥ 1 language */
inline constexpr detail::no_reassign_spec no_reassign{}; /**< @see welder::detail::no_reassign_spec */
inline constexpr detail::trust_bindable_spec trust_bindable{}; /**< @see welder::detail::trust_bindable_spec */
inline constexpr detail::family_surface_spec family_surface{}; /**< @see welder::detail::family_surface_spec */
} // namespace mark

// --- getter / setter: method-backed properties -------------------------------
Expand Down
22 changes: 22 additions & 0 deletions src/welder/reflect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,28 @@ consteval bool trusted_for(std::meta::info member, lang L) {
return false;
}

/** Does welded base class @a type opt its family into a rod-synthesized
version-agnostic surface for language @a L (a `family_surface` mark)?

Synthesizing members onto a base is strictly opt-in (see
detail::family_surface_spec): a rod implementing family surfaces must
synthesize nothing for a base that does not carry the mark. welder core
only stores and answers this query; the surface itself is the honoring
rod's contract.
@param type a reflection of the welded base class to test.
@param L the target language.
@return `true` iff a `family_surface` mark covers @a L (mask `0` covers
all languages). */
consteval bool family_surface_for(std::meta::info type, lang L) {
for (auto a : std::meta::annotations_of_with_type(
type, ^^detail::family_surface_spec)) {
auto s{std::meta::extract<detail::family_surface_spec>(a)};
if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
return true;
}
return false;
}

/** Is data member @a member bound **read-only** for @a L by a `no_reassign` mark?

`no_reassign` forces the read-only binding on a mutable member (see
Expand Down
14 changes: 14 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ add_test(NAME compile.user_lang
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
--target welder_user_lang --config $<CONFIG>)

# The family_surface TYPE mark (compile-only): a welded base's opt-in to
# rod-synthesized version-agnostic family surfaces. Locks storage + the
# family_surface_for query: bare = all languages (user-minted included),
# scoped = exactly the named ones, repeats union, unmarked = false — the
# opt-in default an honoring rod must respect by synthesizing nothing.
add_library(welder_family_surface_mark OBJECT EXCLUDE_FROM_ALL
core/family_surface_mark.cpp)
target_compile_features(welder_family_surface_mark PRIVATE cxx_std_26)
target_link_libraries(welder_family_surface_mark PRIVATE welder::headers
welder_warnings)
add_test(NAME compile.family_surface_mark
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
--target welder_family_surface_mark --config $<CONFIG>)

# Template ↔ annotation semantics (compile-only): annotations on a template
# declaration are readable through every *instantiation* (primary / partial /
# explicit precedence; member, weld/mark and parameter annotations included) —
Expand Down
59 changes: 59 additions & 0 deletions tests/core/family_surface_mark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// The family_surface mark (compile-only; must SUCCEED).
//
// Locks the storage + query contract of `[[=welder::mark::family_surface]]`:
// the TYPE mark a welded base carries to opt its family (two or more welded
// classes deriving it) into a rod-synthesized version-agnostic surface.
// welder core only stores and answers `family_surface_for`; the surface
// itself is the honoring rod's contract (the C# rod's dispatch members are
// the first). The semantics locked here:
// - bare mark -> covers every language, shipped and user-minted alike;
// - scoped mark -> covers exactly the named languages;
// - repeated marks union their languages;
// - an unmarked base answers false everywhere — the opt-in default a rod
// must respect by synthesizing nothing.
#include <welder/vocabulary.hpp>
#include <welder/reflect.hpp> // family_surface_for

namespace {

inline constexpr welder::lang ruby{welder::user_lang<0>};

struct [[=welder::weld]] PlainBase {};

struct
[[=welder::weld]]
[[=welder::mark::family_surface]]
BareBase {};

struct
[[=welder::weld]]
[[=welder::mark::family_surface(welder::lang::py)]]
PyBase {};

struct
[[=welder::weld]]
[[=welder::mark::family_surface(welder::lang::py)]]
[[=welder::mark::family_surface(ruby)]]
UnionBase {};

// Unmarked: the opt-in default — false for every language.
static_assert(!welder::family_surface_for(^^PlainBase, welder::lang::py));
static_assert(!welder::family_surface_for(^^PlainBase, welder::lang::lua));
static_assert(!welder::family_surface_for(^^PlainBase, ruby));

// Bare: every language, user-minted ones included.
static_assert(welder::family_surface_for(^^BareBase, welder::lang::py));
static_assert(welder::family_surface_for(^^BareBase, welder::lang::lua));
static_assert(welder::family_surface_for(^^BareBase, ruby));

// Scoped: exactly the named languages.
static_assert(welder::family_surface_for(^^PyBase, welder::lang::py));
static_assert(!welder::family_surface_for(^^PyBase, welder::lang::lua));
static_assert(!welder::family_surface_for(^^PyBase, ruby));

// Repeated marks union.
static_assert(welder::family_surface_for(^^UnionBase, welder::lang::py));
static_assert(welder::family_surface_for(^^UnionBase, ruby));
static_assert(!welder::family_surface_for(^^UnionBase, welder::lang::lua));

} // namespace
Loading