6
6
DataModel ,
7
7
DataModelField ,
8
8
DataModelFieldType ,
9
+ Enum ,
9
10
EnumField ,
10
11
Expression ,
11
12
FunctionDecl ,
@@ -16,6 +17,7 @@ import {
16
17
isDataModel ,
17
18
isDataModelField ,
18
19
isDataModelFieldType ,
20
+ isEnum ,
19
21
isReferenceExpr ,
20
22
LiteralExpr ,
21
23
MemberAccessExpr ,
@@ -164,6 +166,10 @@ export class ZModelLinker extends DefaultLinker {
164
166
this . resolveDataModel ( node as DataModel , document , extraScopes ) ;
165
167
break ;
166
168
169
+ case DataModelField :
170
+ this . resolveDataModelField ( node as DataModelField , document , extraScopes ) ;
171
+ break ;
172
+
167
173
default :
168
174
this . resolveDefault ( node , document , extraScopes ) ;
169
175
break ;
@@ -451,6 +457,49 @@ export class ZModelLinker extends DefaultLinker {
451
457
return this . resolveDefault ( node , document , extraScopes ) ;
452
458
}
453
459
460
+ private resolveDataModelField (
461
+ node : DataModelField ,
462
+ document : LangiumDocument < AstNode > ,
463
+ extraScopes : ScopeProvider [ ]
464
+ ) {
465
+ // Field declaration may contain enum references, and enum fields are pushed to the global
466
+ // scope, so if there're enums with fields with the same name, an arbitrary one will be
467
+ // used as resolution target. The correct behavior is to resolve to the enum that's used
468
+ // as the declaration type of the field:
469
+ //
470
+ // enum FirstEnum {
471
+ // E1
472
+ // E2
473
+ // }
474
+
475
+ // enum SecondEnum {
476
+ // E1
477
+ // E3
478
+ // E4
479
+ // }
480
+
481
+ // model M {
482
+ // id Int @id
483
+ // first SecondEnum @default (E1) <- should resolve to SecondEnum
484
+ // second FirstEnum @default (E1) <- should resolve to FirstEnum
485
+ // }
486
+ //
487
+
488
+ // make sure type is resolved first
489
+ this . resolve ( node . type , document , extraScopes ) ;
490
+
491
+ let scopes = extraScopes ;
492
+
493
+ // if the field has enum declaration type, resolve the rest with that enum's fields on top of the scopes
494
+ if ( node . type . reference ?. ref && isEnum ( node . type . reference . ref ) ) {
495
+ const contextEnum = node . type . reference . ref as Enum ;
496
+ const enumScope : ScopeProvider = ( name ) => contextEnum . fields . find ( ( f ) => f . name === name ) ;
497
+ scopes = [ enumScope , ...scopes ] ;
498
+ }
499
+
500
+ this . resolveDefault ( node , document , scopes ) ;
501
+ }
502
+
454
503
private resolveDefault ( node : AstNode , document : LangiumDocument < AstNode > , extraScopes : ScopeProvider [ ] ) {
455
504
for ( const [ property , value ] of Object . entries ( node ) ) {
456
505
if ( ! property . startsWith ( '$' ) ) {
0 commit comments