@sap/cds-compiler 3.6.2 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +109 -1
  2. package/README.md +3 -0
  3. package/bin/cdsc.js +12 -5
  4. package/doc/CHANGELOG_ARCHIVE.md +6 -6
  5. package/doc/CHANGELOG_BETA.md +35 -2
  6. package/doc/CHANGELOG_DEPRECATED.md +2 -2
  7. package/doc/DeprecatedOptions_v2.md +1 -1
  8. package/doc/NameResolution.md +1 -1
  9. package/lib/api/main.js +63 -23
  10. package/lib/api/options.js +1 -0
  11. package/lib/api/validate.js +5 -0
  12. package/lib/base/dictionaries.js +15 -3
  13. package/lib/base/keywords.js +2 -0
  14. package/lib/base/message-registry.js +120 -34
  15. package/lib/base/messages.js +51 -27
  16. package/lib/base/model.js +4 -2
  17. package/lib/base/shuffle.js +2 -1
  18. package/lib/checks/arrayOfs.js +1 -1
  19. package/lib/checks/defaultValues.js +1 -1
  20. package/lib/checks/elements.js +29 -1
  21. package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +10 -6
  22. package/lib/checks/invalidTarget.js +1 -1
  23. package/lib/checks/nonexpandableStructured.js +1 -1
  24. package/lib/checks/onConditions.js +15 -9
  25. package/lib/checks/sql-snippets.js +2 -2
  26. package/lib/checks/types.js +5 -1
  27. package/lib/checks/validator.js +7 -3
  28. package/lib/compiler/assert-consistency.js +42 -26
  29. package/lib/compiler/base.js +50 -4
  30. package/lib/compiler/builtins.js +17 -8
  31. package/lib/compiler/checks.js +241 -246
  32. package/lib/compiler/define.js +113 -146
  33. package/lib/compiler/extend.js +889 -383
  34. package/lib/compiler/finalize-parse-cdl.js +5 -58
  35. package/lib/compiler/index.js +1 -1
  36. package/lib/compiler/kick-start.js +7 -8
  37. package/lib/compiler/populate.js +297 -293
  38. package/lib/compiler/propagator.js +27 -18
  39. package/lib/compiler/resolve.js +146 -463
  40. package/lib/compiler/shared.js +36 -79
  41. package/lib/compiler/tweak-assocs.js +30 -28
  42. package/lib/compiler/utils.js +31 -5
  43. package/lib/edm/annotations/genericTranslation.js +131 -59
  44. package/lib/edm/annotations/preprocessAnnotations.js +3 -0
  45. package/lib/edm/csn2edm.js +22 -5
  46. package/lib/edm/edm.js +6 -4
  47. package/lib/edm/edmAnnoPreprocessor.js +1 -0
  48. package/lib/edm/edmPreprocessor.js +42 -26
  49. package/lib/gen/Dictionary.json +38 -2
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +3 -1
  52. package/lib/gen/languageLexer.js +1 -1
  53. package/lib/gen/languageParser.js +4828 -4472
  54. package/lib/inspect/inspectPropagation.js +20 -34
  55. package/lib/json/from-csn.js +140 -44
  56. package/lib/json/to-csn.js +114 -122
  57. package/lib/language/errorStrategy.js +2 -0
  58. package/lib/language/genericAntlrParser.js +156 -36
  59. package/lib/language/language.g4 +100 -58
  60. package/lib/language/textUtils.js +13 -0
  61. package/lib/main.d.ts +43 -3
  62. package/lib/main.js +4 -2
  63. package/lib/model/csnRefs.js +15 -3
  64. package/lib/model/csnUtils.js +12 -74
  65. package/lib/model/revealInternalProperties.js +4 -2
  66. package/lib/modelCompare/compare.js +2 -1
  67. package/lib/optionProcessor.js +3 -0
  68. package/lib/render/manageConstraints.js +5 -2
  69. package/lib/render/toCdl.js +216 -104
  70. package/lib/render/toHdbcds.js +2 -9
  71. package/lib/render/toRename.js +14 -51
  72. package/lib/render/toSql.js +4 -3
  73. package/lib/render/utils/common.js +9 -5
  74. package/lib/transform/braceExpression.js +6 -0
  75. package/lib/transform/db/assertUnique.js +2 -1
  76. package/lib/transform/db/expansion.js +2 -0
  77. package/lib/transform/db/flattening.js +37 -36
  78. package/lib/transform/db/rewriteCalculatedElements.js +600 -0
  79. package/lib/transform/db/transformExists.js +4 -0
  80. package/lib/transform/db/views.js +40 -37
  81. package/lib/transform/forOdataNew.js +20 -15
  82. package/lib/transform/forRelationalDB.js +58 -41
  83. package/lib/transform/odata/typesExposure.js +50 -15
  84. package/lib/transform/parseExpr.js +16 -8
  85. package/lib/transform/transformUtilsNew.js +42 -14
  86. package/lib/transform/translateAssocsToJoins.js +60 -37
  87. package/lib/transform/universalCsn/coreComputed.js +15 -7
  88. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  89. package/package.json +2 -1
@@ -119,7 +119,11 @@
119
119
 
120
120
  'use strict';
121
121
 
122
- const { forEachGeneric, forEachInOrder, isBetaEnabled } = require('../base/model');
122
+ const {
123
+ forEachGeneric,
124
+ forEachInOrder,
125
+ forEachMember,
126
+ } = require('../base/model');
123
127
  const shuffleGen = require('../base/shuffle');
124
128
  const {
125
129
  dictAdd, dictAddArray, dictForEach, pushToDict,
@@ -132,7 +136,6 @@ const {
132
136
  dependsOnSilent,
133
137
  pathName,
134
138
  splitIntoPath,
135
- annotationHasEllipsis,
136
139
  isDirectComposition,
137
140
  } = require('./utils');
138
141
  const { compareLayer } = require('./moduleLayers');
@@ -160,19 +163,15 @@ function define( model ) {
160
163
  } = model.$messageFunctions;
161
164
  const {
162
165
  resolveUncheckedPath,
163
- checkAnnotate,
164
166
  } = model.$functions;
165
167
  const { shuffleDict, shuffleArray } = shuffleGen( options.testMode );
166
168
 
167
- const extensionsDict = Object.create(null);
168
169
  Object.assign( model.$functions, {
169
170
  shuffleDict,
170
171
  shuffleArray,
171
172
  initArtifact,
172
173
  initMembers,
173
- extensionsDict, // a dictionary - TODO: put directly into model?
174
- checkDefinitions,
175
- initAnnotations,
174
+ checkDefinitions, // TODO: remove
176
175
  } );
177
176
  // During the definer, we can only resolve artifact references, i.e,
178
177
  // after a `.`, we only search in the `_subArtifacts` dictionary:
@@ -202,7 +201,7 @@ function define( model ) {
202
201
  setLink( model, '_entities', [] ); // for entities with includes
203
202
  model.$entity = 0;
204
203
  model.$compositionTargets = Object.create(null);
205
- model.$lateExtensions = Object.create(null); // for generated artifacts
204
+ model.$lateExtensions = Object.create(null); // TODO: rename to $collectedExtensions
206
205
 
207
206
  initBuiltins( model );
208
207
  const sourceNames = shuffleArray( Object.keys( model.sources ) );
@@ -212,7 +211,7 @@ function define( model ) {
212
211
  initNamespaceAndUsing( model.sources[name] );
213
212
  dictForEach( model.definitions, initArtifact );
214
213
  dictForEach( model.vocabularies, initVocabulary );
215
- dictForEach( extensionsDict, initExtension );
214
+ dictForEach( model.$lateExtensions, e => e._extensions.forEach( initExtension ) );
216
215
 
217
216
  addI18nBlocks();
218
217
  }
@@ -398,19 +397,52 @@ function define( model ) {
398
397
  return;
399
398
  delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1
400
399
  ext.name.absolute = absolute; // definition might not be there yet, no _artifact link
401
- pushToDict( extensionsDict, absolute, ext );
400
+ const location = { file: '' }; // stupid required location
401
+ const late = model.$lateExtensions[absolute] ||
402
+ (model.$lateExtensions[absolute] = {
403
+ kind: 'annotate',
404
+ name: { absolute, location },
405
+ $inferred: '',
406
+ location,
407
+ });
408
+ pushToDict( late, '_extensions', ext );
402
409
  if (!ext.artifacts)
403
410
  return;
411
+
404
412
  // Directly add the artifacts of context and service extension:
405
413
  if (!model.$blocks)
406
414
  model.$blocks = Object.create( null );
407
415
  // Set block number for debugging (--raw-output):
408
416
  // eslint-disable-next-line no-multi-assign
409
417
  ext.name.select = model.$blocks[absolute] = (model.$blocks[absolute] || 0) + 1;
418
+ // add "namespace" for the case that ext.artifacts is empty (TODO: later)
419
+ // now add all definitions in ext.artifacts:
410
420
  const prefix = `${ absolute }.`;
411
421
  dictForEach( ext.artifacts, a => addArtifact( a, ext, prefix ) );
412
422
  }
413
423
 
424
+ function initExtension( parent ) {
425
+ forEachMember( parent, function init( sub ) {
426
+ if (sub.kind !== 'extend' && sub.kind !== 'annotate')
427
+ return; // for defs inside, set somewhere else - TODO: rethink
428
+ setLink( sub, '_block', parent._block );
429
+ setLink( sub, '_parent', parent );
430
+ setLink( sub, '_main', parent._main || parent );
431
+ initExtension( sub );
432
+ } );
433
+ if (parent.kind !== 'extend')
434
+ return;
435
+ if (parent.columns) // TODO: sub queries? expand/inline?
436
+ parent.columns.forEach( c => setLink( c, '_block', parent._block ) );
437
+ if (parent.scale && !parent.precision) {
438
+ // TODO: where could we store the location of the name?
439
+ error( 'syntax-missing-type-property', [ parent.scale.location ],
440
+ { prop: 'scale', otherprop: 'precision' },
441
+ 'Type extension with property $(PROP) must also have property $(OTHERPROP)' );
442
+ parent.scale = undefined; // no consequential error
443
+ }
444
+ }
445
+
414
446
  function addVocabulary( vocab, block, prefix ) {
415
447
  setLink( vocab, '_block', block );
416
448
  const { name } = vocab;
@@ -534,13 +566,10 @@ function define( model ) {
534
566
  initArtifactParentLink( art, model.definitions );
535
567
  const block = art._block;
536
568
  checkRedefinition( art );
537
- initAnnotations( art, block );
538
569
  initMembers( art, art, block );
539
570
  initDollarSelf( art ); // $self
540
571
  if (art.params)
541
572
  initDollarParameters( art );
542
- if (art.includes && !(art.name.absolute in extensionsDict)) // TODO: in next phase?
543
- extensionsDict[art.name.absolute] = []; // structure with includes must be "extended"
544
573
 
545
574
  if (!art.query)
546
575
  return;
@@ -548,6 +577,7 @@ function define( model ) {
548
577
  setLink( art, '_from', [] ); // for sequence of resolve steps
549
578
  if (!setLink( art, '_leadingQuery', initQueryExpression( art.query, art ) ) )
550
579
  return; // null or undefined in case of parse error
580
+ // if (art._leadingQuery !== art.$queries [0]) throw Error('FOO');
551
581
  setLink( art._leadingQuery, '_$next', art );
552
582
  if (art.elements) { // specified element via compilation of client-style CSN
553
583
  // TODO: consider this part of a revamped on-demand 'extend' functionality
@@ -560,7 +590,6 @@ function define( model ) {
560
590
  initArtifactParentLink( art, model.vocabularies );
561
591
  checkRedefinition( art );
562
592
  const block = art._block;
563
- initAnnotations( art, block );
564
593
  initMembers( art, art, block );
565
594
  }
566
595
 
@@ -586,57 +615,6 @@ function define( model ) {
586
615
  parent._subArtifacts[absolute.substring( dot + 1 )] = art; // not dictAdd()
587
616
  }
588
617
 
589
- /** Initialize the extension `ext`.
590
- *
591
- * Currently:
592
- *
593
- * - initialize annotations (set _block, $priority, `...` check) on "main"
594
- * extension and its columns do more later
595
- * - for members in compile(): init annotations via extendMembers/annotateMembers
596
- * - for members in parse.cdl(): init annotation via initMembers
597
- *
598
- * In the future (after name cleanup):
599
- *
600
- * - also initialize members and member extensions/annotations here
601
- * - we might also do other things, like calculating whether an `extend` is
602
- * `annotate`-like, i.e. only contains name-resolution irrelevant extensions.
603
- */
604
- function initExtension( ext ) {
605
- const block = ext._block;
606
- initAnnotations( ext, block, ext.kind );
607
- if (ext.columns) // the columns themselves are "definitions"
608
- ext.columns.forEach( col => initAnnotations( col, block ) );
609
- }
610
-
611
- // Set _block links for annotations (necessary for layering) and do a late
612
- // syntax check (`...` only with extensions, not definitions).
613
- // extKind is either ext.kind (=art is extension) or false (=art is not an extension)
614
- function initAnnotations( art, block, extKind = false ) {
615
- // TODO: think of removing $priority, then
616
- // no _block: define, _block: annotate/extend/edmx
617
- // would fit with extending defs with props like length
618
- for (const prop in art) {
619
- if (prop.charAt(0) === '@' || prop === 'doc') {
620
- const anno = art[prop];
621
- // TODO: make anno never be an array, see addAnnotation() in genericAntlrParser
622
- if (Array.isArray( anno ))
623
- anno.forEach( init );
624
- else
625
- init( anno );
626
- }
627
- }
628
- return;
629
-
630
- function init( anno ) {
631
- setLink( anno, '_block', block );
632
- anno.$priority = extKind;
633
- if (!extKind && annotationHasEllipsis( anno )) {
634
- error( 'anno-unexpected-ellipsis',
635
- [ anno.name.location, art ], { code: '...' } );
636
- }
637
- }
638
- }
639
-
640
618
  // Init special things: -------------------------------------------------------
641
619
 
642
620
  function initDollarSelf( art ) {
@@ -708,7 +686,6 @@ function define( model ) {
708
686
  setLink( self, '_origin', query );
709
687
  setLink( self, '_parent', query );
710
688
  setLink( self, '_main', query._main );
711
- setLink( self, '_effectiveType', query ); // TODO: remove
712
689
  query.$tableAliases.$self = self;
713
690
  query.$tableAliases.$projection = self;
714
691
  }
@@ -770,15 +747,16 @@ function define( model ) {
770
747
  // _origin is set when we resolve the ref
771
748
  if (query._parent.kind !== 'select')
772
749
  query._main._from.push( table ); // store tabref if outside "real" subquery
750
+ // (tab refs on the right of union are unnecessary)
773
751
  }
774
752
  else if (table.query) {
775
- if (!table.name || !table.name.id) {
776
- error( 'query-req-alias', [ table.location, query ], {}, // TODO: not subquery.location ?
777
- 'Table alias is required for this subquery' );
778
- return;
753
+ if (!table.name?.id) {
754
+ // We don't worry about duplicate names here.
755
+ const id = `$_select_${ query._main.$queries.length + 1 }__`;
756
+ table.name = { id, location: table.location, $inferred: '$internal' };
757
+ table.$inferred = '$internal';
779
758
  }
780
759
  addAsAlias();
781
- setLink( table, '_effectiveType', table.query ); // TODO: remove!
782
760
  // Store _origin to leading query of table.query for name resolution
783
761
  setLink( table, '_origin', initQueryExpression( table.query, table ) );
784
762
  }
@@ -823,8 +801,15 @@ function define( model ) {
823
801
  table.kind = '$tableAlias';
824
802
  setMemberParent( table, table.name.id, query );
825
803
  setLink( table, '_block', query._block );
826
- dictAdd( query.$tableAliases, table.name.id, table, ( name, loc ) => {
827
- error( 'duplicate-definition', [ loc, table ], { name, '#': 'alias' } );
804
+ dictAdd( query.$tableAliases, table.name.id, table, ( name, loc, tableAlias ) => {
805
+ if (tableAlias.$inferred === '$internal') {
806
+ const semanticLoc = tableAlias.query?.name ? tableAlias.query : tableAlias;
807
+ error( 'name-missing-alias', [ tableAlias.location, semanticLoc ],
808
+ { '#': 'duplicate', code: 'as ‹alias›' });
809
+ }
810
+ else {
811
+ error( 'duplicate-definition', [ loc, table ], { name, '#': 'alias' } );
812
+ }
828
813
  } );
829
814
  // also add to JOIN nodes for name restrictions:
830
815
  for (const p of joinParents) {
@@ -832,7 +817,7 @@ function define( model ) {
832
817
  // already used for duplicate aliases of queries:
833
818
  dictAddArray( p.$tableAliases, table.name.id, table );
834
819
  }
835
- if (table.name.id[0] === '$') {
820
+ if (table.name?.id[0] === '$' && table.name.$inferred !== '$internal') {
836
821
  warning( 'name-invalid-dollar-alias', [ table.name.location, table ], {
837
822
  '#': (table.name.$inferred ? '$tableImplicit' : '$tableAlias'),
838
823
  name: '$',
@@ -935,7 +920,6 @@ function define( model ) {
935
920
  // Either expression (value), expand or new association (target && type)
936
921
  else if (col.value || col.expand || (col.target && col.type)) {
937
922
  setLink( col, '_block', parent._block );
938
- initAnnotations( col, parent._block );
939
923
  if (col.inline) { // `@anno elem.{ * }` does not work
940
924
  if (col.doc) {
941
925
  warning( 'syntax-ignoring-anno', [ col.doc.location, col ],
@@ -1010,12 +994,14 @@ function define( model ) {
1010
994
  *
1011
995
  * If not for extensions: construct === parent
1012
996
  *
997
+ * Param `initExtensions` is for parse.cdl - TODO delete
998
+ *
1013
999
  * TODO: separate extension!
1014
1000
  */
1015
1001
  function initMembers( construct, parent, block, initExtensions = false ) {
1016
1002
  // TODO: split extend from init
1017
1003
  const main = parent._main || parent;
1018
- const isQueryExtension = kindProperties[construct.kind].isExtension && main.query;
1004
+ const isQueryExtension = construct.kind === 'extend' && main.query;
1019
1005
  let obj = construct;
1020
1006
  let { items } = obj;
1021
1007
  while (items) {
@@ -1043,46 +1029,8 @@ function define( model ) {
1043
1029
  'A managed aspect composition can\'t have a specified ON-condition' );
1044
1030
  delete obj.on; // continuation semantics: not specified
1045
1031
  }
1046
- if (targetAspect.elements) {
1047
- // TODO: main?
1048
- const inEntity = parent._main && parent._main.kind === 'entity';
1049
- // TODO: also allow indirectly (component in component in entity)?
1050
- setLink( targetAspect, '_outer', obj );
1051
- setLink( targetAspect, '_parent', parent._parent );
1052
- setLink( targetAspect, '_main', null ); // for name resolution
1053
-
1054
- parent = targetAspect;
1055
- construct = parent; // avoid extension behavior
1056
- targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
1057
- setLink( targetAspect, '_block', block );
1058
- initDollarSelf( targetAspect );
1059
- // allow ref of up_ in anonymous aspect inside entity
1060
- // (TODO: complain if used and the managed composition is included into
1061
- // another entity - might induce auto-redirection):
1062
- if (inEntity && !targetAspect.elements.up_) {
1063
- const up = {
1064
- name: {
1065
- id: 'up_',
1066
- alias: 'up_',
1067
- element: obj.name.element,
1068
- absolute: obj.name.absolute,
1069
- },
1070
- kind: '$navElement',
1071
- location: obj.location,
1072
- };
1073
- setLink( up, '_parent', targetAspect );
1074
- setLink( up, '_main', targetAspect ); // used on main artifact
1075
- // recompilation case: both target and targetAspect → allow up_ in that case, too:
1076
- const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
1077
- const entity = name && model.definitions[name];
1078
- if (entity && entity.elements)
1079
- setLink( up, '_origin', entity.elements.up_ );
1080
- // processAspectComposition/expand() sets _origin to element of
1081
- // generated target entity
1082
- targetAspect.$tableAliases.up_ = up;
1083
- }
1084
- obj = targetAspect;
1085
- }
1032
+ if (targetAspect.elements)
1033
+ initAnonymousAspect();
1086
1034
  }
1087
1035
  if (obj !== parent && obj.elements && parent.enum) { // applying the extension
1088
1036
  initElementsAsEnum();
@@ -1102,7 +1050,8 @@ function define( model ) {
1102
1050
  forEachInOrder( construct, 'params', init );
1103
1051
  const { returns } = construct;
1104
1052
  if (returns) {
1105
- returns.kind = (kindProperties[construct.kind].isExtension) ? construct.kind : 'param';
1053
+ const { kind } = construct;
1054
+ returns.kind = (kind === 'extend' || kind === 'annotate') ? kind : 'param';
1106
1055
  init( returns, '' ); // '' is special name for returns parameter
1107
1056
  }
1108
1057
  return;
@@ -1129,6 +1078,47 @@ function define( model ) {
1129
1078
  forEachGeneric( { enum: obj.elements }, 'enum', init );
1130
1079
  }
1131
1080
 
1081
+ function initAnonymousAspect() {
1082
+ // TODO: main?
1083
+ const inEntity = parent._main && parent._main.kind === 'entity';
1084
+ // TODO: also allow indirectly (component in component in entity)?
1085
+ setLink( targetAspect, '_outer', obj );
1086
+ setLink( targetAspect, '_parent', parent._parent );
1087
+ setLink( targetAspect, '_main', null ); // for name resolution
1088
+
1089
+ parent = targetAspect;
1090
+ construct = parent; // avoid extension behavior
1091
+ targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
1092
+ setLink( targetAspect, '_block', block );
1093
+ initDollarSelf( targetAspect );
1094
+ // allow ref of up_ in anonymous aspect inside entity
1095
+ // (TODO: complain if used and the managed composition is included into
1096
+ // another entity - might induce auto-redirection):
1097
+ if (inEntity && !targetAspect.elements.up_) {
1098
+ const up = {
1099
+ name: {
1100
+ id: 'up_',
1101
+ alias: 'up_',
1102
+ element: obj.name.element,
1103
+ absolute: obj.name.absolute,
1104
+ },
1105
+ kind: '$navElement',
1106
+ location: obj.location,
1107
+ };
1108
+ setLink( up, '_parent', targetAspect );
1109
+ setLink( up, '_main', targetAspect ); // used on main artifact
1110
+ // recompilation case: both target and targetAspect → allow up_ in that case, too:
1111
+ const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
1112
+ const entity = name && model.definitions[name];
1113
+ if (entity && entity.elements)
1114
+ setLink( up, '_origin', entity.elements.up_ );
1115
+ // processAspectComposition/expand() sets _origin to element of
1116
+ // generated target entity
1117
+ targetAspect.$tableAliases.up_ = up;
1118
+ }
1119
+ obj = targetAspect;
1120
+ }
1121
+
1132
1122
  function init( elem, name, prop ) {
1133
1123
  if (!elem.kind) // wrong CSN input
1134
1124
  elem.kind = dictKinds[prop];
@@ -1138,12 +1128,12 @@ function define( model ) {
1138
1128
  elem.name = Object.assign( { $inferred: 'as' },
1139
1129
  ref.path[ref.path.length - 1] );
1140
1130
  }
1141
- else { // if JSON parser misses to set name
1131
+ else { // RETURNS, parser robustness
1142
1132
  elem.name = { id: name, location: elem.location };
1143
1133
  }
1144
1134
  }
1145
1135
  // if (!kindProperties[ elem.kind ]) console.log(elem.kind,elem.name)
1146
- if (kindProperties[elem.kind].isExtension && !initExtensions) {
1136
+ if ((elem.kind === 'extend' || elem.kind === 'annotate') && !initExtensions) {
1147
1137
  storeExtension( elem, name, prop, parent, block );
1148
1138
  return;
1149
1139
  }
@@ -1161,9 +1151,6 @@ function define( model ) {
1161
1151
  setMemberParent( elem, name, parent, add && prop );
1162
1152
  // console.log(message( null, elem.location, elem, {}, 'Info', 'INIT').toString())
1163
1153
  checkRedefinition( elem );
1164
- if (elem.kind === 'annotate' || elem.kind === 'extend')
1165
- checkAnnotate( elem, elem );
1166
- initAnnotations( elem, bl );
1167
1154
  initMembers( elem, elem, bl, initExtensions );
1168
1155
  if (boundSelfParamType && (elem.kind === 'action' || elem.kind === 'function'))
1169
1156
  initBoundSelfParam( elem.params );
@@ -1174,31 +1161,11 @@ function define( model ) {
1174
1161
  elem.$syntax === 'enum' && parent.kind === 'extend') // ambiguous in parse-cdl
1175
1162
  return;
1176
1163
  // -> it's a calculated element
1177
- checkCalculatedElement(elem);
1178
- elem.$syntax = 'calc';
1179
- }
1180
- }
1181
-
1182
- function checkCalculatedElement( elem ) {
1183
- const loc = [ elem.value.location, elem ];
1184
- if (elem._main.kind !== 'entity' && elem._main.kind !== 'aspect' &&
1185
- elem._main.kind !== 'extend') {
1186
- error( 'syntax-invalid-calc-elem', loc, { '#': elem._main.kind } );
1187
- }
1188
- else if (!isBetaEnabled( options, 'calculatedElements' )) {
1189
- error( 'def-unsupported-calc-elem', loc,
1190
- 'Calculated elements are not supported' );
1191
- }
1192
- else {
1193
- const noTruthyAllowed = [ 'localized', 'key', 'virtual' ];
1194
- for (const prop of noTruthyAllowed) {
1195
- if (elem[prop]?.val) {
1196
- // probably better than a parse error (which is good for DEFAULT vs calc),
1197
- // also appears with parse-cdl:
1198
- error('syntax-invalid-calc-elem', loc, { '#': prop });
1199
- return; // one error is enough
1200
- }
1164
+ if (!elem.type && elem.value?.type) { // top-level CAST( expr AS type )
1165
+ if (!elem.target)
1166
+ elem.type = { ...elem.value.type, $inferred: 'cast' };
1201
1167
  }
1168
+ elem.$syntax = 'calc';
1202
1169
  }
1203
1170
  }
1204
1171