@@ -11,7 +11,7 @@ import type { LangiumDocument, LangiumDocuments } from '../workspace/documents.j
1111import type { ScopeProvider } from './scope-provider.js' ;
1212import { CancellationToken } from '../utils/cancellation.js' ;
1313import { isAstNode , isAstNodeDescription , isLinkingError } from '../syntax-tree.js' ;
14- import { getDocument , streamAst , streamReferences } from '../utils/ast-utils.js' ;
14+ import { findRootNode , streamAst , streamReferences } from '../utils/ast-utils.js' ;
1515import { interruptAndCheck } from '../utils/promise-utils.js' ;
1616import { DocumentState } from '../workspace/documents.js' ;
1717
@@ -67,8 +67,10 @@ export interface Linker {
6767
6868}
6969
70+ const ref_resolving = Symbol ( 'ref_resolving' ) ;
71+
7072interface DefaultReference extends Reference {
71- _ref ?: AstNode | LinkingError ;
73+ _ref ?: AstNode | LinkingError | typeof ref_resolving ;
7274 _nodeDescription ?: AstNodeDescription ;
7375}
7476
@@ -96,6 +98,7 @@ export class DefaultLinker implements Linker {
9698 const ref = refInfo . reference as DefaultReference ;
9799 // The reference may already have been resolved lazily by accessing its `ref` property.
98100 if ( ref . _ref === undefined ) {
101+ ref . _ref = ref_resolving ;
99102 try {
100103 const description = this . getCandidate ( refInfo ) ;
101104 if ( isLinkingError ( description ) ) {
@@ -106,12 +109,17 @@ export class DefaultLinker implements Linker {
106109 // The target document is already loaded
107110 const linkedNode = this . loadAstNode ( description ) ;
108111 ref . _ref = linkedNode ?? this . createLinkingError ( refInfo , description ) ;
112+ } else {
113+ // Try to load the target AST node later using the already provided description
114+ ref . _ref = undefined ;
109115 }
110116 }
111117 } catch ( err ) {
118+ console . error ( `An error occurred while resolving reference to '${ ref . $refText } ':` , err ) ;
119+ const errorMessage = ( err as Error ) . message ?? String ( err ) ;
112120 ref . _ref = {
113121 ...refInfo ,
114- message : `An error occurred while resolving reference to '${ ref . $refText } ': ${ err } `
122+ message : `An error occurred while resolving reference to '${ ref . $refText } ': ${ errorMessage } `
115123 } ;
116124 }
117125 // Add the reference to the document's array of references
@@ -155,15 +163,18 @@ export class DefaultLinker implements Linker {
155163 linker . createLinkingError ( { reference, container : node , property } , this . _nodeDescription ) ;
156164 } else if ( this . _ref === undefined ) {
157165 // The reference has not been linked yet, so do that now.
166+ this . _ref = ref_resolving ;
167+ const document = findRootNode ( node ) . $document ;
158168 const refData = linker . getLinkedNode ( { reference, container : node , property } ) ;
159- if ( refData . error && getDocument ( node ) . state < DocumentState . ComputedScopes ) {
169+ if ( refData . error && document && document . state < DocumentState . ComputedScopes ) {
160170 // Document scope is not ready, don't set `this._ref` so linker can retry later.
161- return undefined ;
171+ return this . _ref = undefined ;
162172 }
163173 this . _ref = refData . node ?? refData . error ;
164174 this . _nodeDescription = refData . descr ;
165- const document = getDocument ( node ) ;
166- document . references . push ( this ) ;
175+ document ?. references . push ( this ) ;
176+ } else if ( this . _ref === ref_resolving ) {
177+ throw new Error ( `Cyclic reference resolution detected: ${ linker . astNodeLocator . getAstNodePath ( node ) } /${ property } (symbol '${ refText } ')` ) ;
167178 }
168179 return isAstNode ( this . _ref ) ? this . _ref : undefined ;
169180 } ,
@@ -195,10 +206,12 @@ export class DefaultLinker implements Linker {
195206 } ;
196207 }
197208 } catch ( err ) {
209+ console . error ( `An error occurred while resolving reference to '${ refInfo . reference . $refText } ':` , err ) ;
210+ const errorMessage = ( err as Error ) . message ?? String ( err ) ;
198211 return {
199212 error : {
200213 ...refInfo ,
201- message : `An error occurred while resolving reference to '${ refInfo . reference . $refText } ': ${ err } `
214+ message : `An error occurred while resolving reference to '${ refInfo . reference . $refText } ': ${ errorMessage } `
202215 }
203216 } ;
204217 }
@@ -218,8 +231,8 @@ export class DefaultLinker implements Linker {
218231 protected createLinkingError ( refInfo : ReferenceInfo , targetDescription ?: AstNodeDescription ) : LinkingError {
219232 // Check whether the document is sufficiently processed by the DocumentBuilder. If not, this is a hint for a bug
220233 // in the language implementation.
221- const document = getDocument ( refInfo . container ) ;
222- if ( document . state < DocumentState . ComputedScopes ) {
234+ const document = findRootNode ( refInfo . container ) . $document ;
235+ if ( document && document . state < DocumentState . ComputedScopes ) {
223236 console . warn ( `Attempted reference resolution before document reached ComputedScopes state (${ document . uri } ).` ) ;
224237 }
225238 const referenceType = this . reflection . getReferenceType ( refInfo ) ;
0 commit comments