Skip to content

Conversation

@msujew
Copy link
Member

@msujew msujew commented May 23, 2024

Adds support for multi-target references. These are references that have the possibility to target multiple elements at once. See following illustration for an example:

image

Note that by default, only elements that are defined on the same scope can be targeted. I.e. a multi reference as in the following will only target one element:

image

This behavior can be freely overwritten by adopters of Langium. However, due to the inherent complexity of aligning the References service implementation and the scoping wrt their behavior, this feature is intended for proficient Langium developers.

The intended use cases for this feature are stuff like declaration merging in TypeScript or partial classes in C#.

Contains a bunch of breaking changes:

  • The whole References interface now returns arrays instead of T | undefined.
  • Every service/interface/class that works with Reference in a generic manner (linker mostly) now also works with MultiReference.
  • LinkingError no longer inherits ReferenceInfo (which didn't make a lot of sense in the first place), but contains a info property.

@msujew msujew added the linking Linking related issue label May 23, 2024
@msujew
Copy link
Member Author

msujew commented May 23, 2024

cc @cdietrich since you were interested in this feature.

@msujew msujew force-pushed the msujew/multi-reference branch from 5912b62 to 942f802 Compare May 23, 2024 13:34
@spoenemann spoenemann self-requested a review May 23, 2024 15:00
Copy link
Contributor

@Lotes Lotes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good, I like especially that one can now ask for an array and do not need to check for undefined when getting references :D.
All in all I added some code improvement suggestions.
I would suggest to wait for more feedback, since I am not so deep in this area of the code, yet.

if (description) {
descr.push(description);
streamReferences(astNode).forEach(refInfo => {
if (!refInfo.reference.error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the diff: I would prefer a !isLinkingError(refInfo). Looks more official.

} else if (isMultiReference(reference)) {
return reference.items.map(item => item.ref);
}
return [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this line ever be reached? What do you think about assertUnreachable?


if (isReference(reference)) {
return reference.ref;
if (isReference(reference) || isMultiReference(reference)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I saw this double call several times now. Would it make sense to introduce something that addresses both?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or breaking the API by introducing isReference (for both; or isAnyReference), isSingleReference and isMultiReference

@msujew msujew mentioned this pull request Oct 14, 2024
Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be possible to realize this in a way that most adopters of Langium won't notice a lot of changes. The actual core changes are not too large, and are mostly adding, but not changing API (we can try to add instead of change in a few more places). I'll have a more detailed look at this within the next two months.

@spoenemann spoenemann added this to the v4.0.0 milestone Feb 5, 2025
@msujew msujew force-pushed the msujew/multi-reference branch 2 times, most recently from 844da20 to 489e234 Compare June 2, 2025 13:27
Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a missing grammar validation: reference type (single or multi) matches declaration (or is consistent with other inferred occurrences).

@msujew msujew force-pushed the msujew/multi-reference branch from 489e234 to bdcf9b2 Compare June 18, 2025 13:07
Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This validation should still be added: #1509 (review)

@msujew msujew requested a review from spoenemann June 19, 2025 09:30
Copy link
Contributor

@spoenemann spoenemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now inconsistent usage of references are detected, but not the consistency of assignment vs. declaration:

interface Entity {
    name: string
    superType: @Entity
    features: Feature[]
}

Entity returns Entity:
    'entity' name=ID ('extends' superType=[+Entity:QualifiedName])? '{'
        (features+=Feature)*
    '}';

This should error because the declared property is a single-reference, but the assigned property is a multi-reference.

@msujew msujew requested a review from spoenemann June 23, 2025 13:40
@msujew msujew merged commit b85f1b5 into main Jun 25, 2025
5 checks passed
@spoenemann spoenemann deleted the msujew/multi-reference branch June 27, 2025 07:13
_nodeDescription?: AstNodeDescription;
}

export interface DefaultMultiReference extends MultiReference {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msujew what was the reasoning behind exporting this one but not the one above

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reason, I thought it makes sense, and forgot that the other one isn't exported yet. Would you like to have both exported?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we are looking into writing linking traps and currently (3.5) we need to c&p everything

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linking Linking related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants