Skip to content
Open
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixed

- `validateFunctionResultParameterMembership` and `validateExpressionResultParameterMembership` count the inherited return parameters too (KerML 8.3.4.7.3, 8.3.4.7.4: "owned or inherited"), so `function G :> F, H;` is reported where `F` and `H` each own one. An owned return parameter redefines those of the general types (`checkFeatureResultRedefinition`), so only the most specific owners count; owners in the library are left out, because the checks do not read the implied specializations that link a type to its library base.

## v0.11.3

### Added
Expand Down
30 changes: 30 additions & 0 deletions crates/sysmlv2-model/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,36 @@ mod tests {
assert_eq!(shown(&on_threads), shown(&in_line));
}

/// KerML 8.3.4.7 validateFunctionResultParameterMembership and
/// validateExpressionResultParameterMembership count the owned and
/// the inherited return parameters. An owned one redefines those of
/// the general types, so only the most specific owners count.
#[test]
fn inherited_return_parameters_count() {
let mut model = Model::new();
model.add_source(
"user.kerml",
"package P {
function F { return r; }
function H { return s; }
function G :> F, H;
function K :> F, H { return t; }
function M :> F;
function N :> M, F;
function T { return a; return b; }
expr X { return x; }
expr Y { return y; }
expr Z :> X, Y;
}",
);
let found: Vec<String> = findings(&model)
.into_iter()
.map(|(_, m)| m)
.filter(|m| m.contains("return parameter"))
.collect();
assert_eq!(found.len(), 3, "{found:?}");
}

#[test]
fn semantic_checks_walk_tables_without_copying_them() {
// Fresh build: library rows and user rows share one storage.
Expand Down
34 changes: 28 additions & 6 deletions crates/sysmlv2-model/src/check/structural.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,14 +475,36 @@ pub(super) fn validate(r: &ResolvedModel, model: &Model, g: &Facts) -> Vec<(usiz
"Only one owned or inherited result expression is allowed",
);
}
let returns = g.members[e]
// An owned return parameter redefines those of the general
// types, so only the most specific owners in the closure count.
// The facts hold no implied specializations, which link a type
// to its library base, so owners in the library are left out.
let owned_returns = |t: usize| {
g.members[t]
.iter()
.filter(|&&m| {
b.elements[m]
.owning_relationship
.is_some_and(|r| b.elements[r].ty == "ReturnParameterMembership")
})
.count()
};
let owners: Vec<(usize, usize)> = g
.closure(e)
.into_iter()
.filter(|&t| t >= b.lib_boundary)
.map(|t| (t, owned_returns(t)))
.filter(|&(_, n)| n > 0)
.collect();
let returns: usize = owners
.iter()
.filter(|&&m| {
b.elements[m]
.owning_relationship
.is_some_and(|r| b.elements[r].ty == "ReturnParameterMembership")
.filter(|&&(t, _)| {
!owners
.iter()
.any(|&(u, _)| u != t && g.closure_shared(u).contains(&t))
})
.count();
.map(|&(_, n)| n)
.sum();
if returns > 1 {
report(
e,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3856,6 +3856,13 @@
"stage": "semantics",
"start": 234
},
{
"end": 235,
"message": "Only one return parameter is allowed [validateExpressionResultParameterMembership]",
"severity": "Error",
"stage": "semantics",
"start": 234
},
{
"end": 244,
"message": "CalculationUsage must have exactly one non-redundant type; found 2",
Expand Down
7 changes: 7 additions & 0 deletions crates/sysmlv2-parser/tests/fixtures/opensysml/baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -4059,6 +4059,13 @@
"stage": "semantics",
"start": 234
},
{
"end": 235,
"message": "Only one return parameter is allowed [validateExpressionResultParameterMembership]",
"severity": "Error",
"stage": "semantics",
"start": 234
},
{
"end": 244,
"message": "CalculationUsage must have exactly one non-redundant type; found 2",
Expand Down