diff --git a/ivette/Makefile b/ivette/Makefile
index 29010215b7bddf4c90c1036b10c4c090a1818e0f..a30dcad4c5f3265efb03fb9bdf283e93d0243a8f 100644
--- a/ivette/Makefile
+++ b/ivette/Makefile
@@ -35,7 +35,7 @@ tsc: dome-pkg dome-templ
 
 api:
 	@echo "[Ivette] Generating TypeScript API"
-	@find api -name "*.ts" -exec rm -f {} \;
+	@rm -fr api/generated
 	../bin/frama-c.byte -load-module api/server_tsc.ml -server-tsc
 	@find api -name "*.ts" -exec chmod a-w {} \;
 
diff --git a/ivette/api/generated/kernel/ast/index.ts b/ivette/api/generated/kernel/ast/index.ts
index 2a910fb94ae5a99b0f515c71fca9aff3bfa3da03..2bd3772caab604fb8d9559f6cd3b77ded324dc11 100644
--- a/ivette/api/generated/kernel/ast/index.ts
+++ b/ivette/api/generated/kernel/ast/index.ts
@@ -120,7 +120,7 @@ export const markerVarTags: Server.GetRequest<null,tag[]>= markerVarTags_interna
 /** Data for array rows [`markerInfo`](#markerinfo)  */
 export interface markerInfoData {
   /** Entry identifier. */
-  key: Json.key<'#markerInfo'>;
+  key: string;
   /** Marker kind */
   kind: markerKind;
   /** Marker variable */
@@ -136,8 +136,7 @@ export interface markerInfoData {
 /** Loose decoder for `markerInfoData` */
 export const jMarkerInfoData: Json.Loose<markerInfoData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#markerInfo'>('#markerInfo'),
-           '#markerInfo expected'),
+    key: Json.jFail(Json.jString,'String expected'),
     kind: jMarkerKindSafe,
     var: jMarkerVarSafe,
     name: Json.jFail(Json.jString,'String expected'),
@@ -152,8 +151,8 @@ export const jMarkerInfoDataSafe: Json.Safe<markerInfoData> =
 /** Natural order for `markerInfoData` */
 export const byMarkerInfoData: Compare.Order<markerInfoData> =
   Compare.byFields
-    <{ key: Json.key<'#markerInfo'>, kind: markerKind, var: markerVar,
-       name: string, descr: string, sloc: source }>({
+    <{ key: string, kind: markerKind, var: markerVar, name: string,
+       descr: string, sloc: source }>({
     key: Compare.string,
     kind: byMarkerKind,
     var: byMarkerVar,
@@ -178,8 +177,8 @@ export const reloadMarkerInfo: Server.GetRequest<null,null>= reloadMarkerInfo_in
 
 const fetchMarkerInfo_internal: Server.GetRequest<
   number,
-  { pending: number, updated: markerInfoData[],
-    removed: Json.key<'#markerInfo'>[], reload: boolean }
+  { pending: number, updated: markerInfoData[], removed: string[],
+    reload: boolean }
   > = {
   kind: Server.RqKind.GET,
   name:   'kernel.ast.fetchMarkerInfo',
@@ -187,21 +186,18 @@ const fetchMarkerInfo_internal: Server.GetRequest<
   output: Json.jObject({
             pending: Json.jFail(Json.jNumber,'Number expected'),
             updated: Json.jList(jMarkerInfoData),
-            removed: Json.jList(Json.jKey<'#markerInfo'>('#markerInfo')),
+            removed: Json.jList(Json.jString),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
 };
 /** Data fetcher for array [`markerInfo`](#markerinfo)  */
 export const fetchMarkerInfo: Server.GetRequest<
   number,
-  { pending: number, updated: markerInfoData[],
-    removed: Json.key<'#markerInfo'>[], reload: boolean }
+  { pending: number, updated: markerInfoData[], removed: string[],
+    reload: boolean }
   >= fetchMarkerInfo_internal;
 
-const markerInfo_internal: State.Array<
-  Json.key<'#markerInfo'>,
-  markerInfoData
-  > = {
+const markerInfo_internal: State.Array<string,markerInfoData> = {
   name: 'kernel.ast.markerInfo',
   getkey: ((d:markerInfoData) => d.key),
   signal: signalMarkerInfo,
@@ -210,7 +206,7 @@ const markerInfo_internal: State.Array<
   order: byMarkerInfoData,
 };
 /** Marker informations */
-export const markerInfo: State.Array<Json.key<'#markerInfo'>,markerInfoData> = markerInfo_internal;
+export const markerInfo: State.Array<string,markerInfoData> = markerInfo_internal;
 
 /** Localizable AST markers */
 export type marker =
diff --git a/ivette/api/generated/kernel/properties/index.ts b/ivette/api/generated/kernel/properties/index.ts
index 7ca5ce68b252ecb5308fe822caec7a05ef680773..dcba1484d490140e593cacd56ab49052929aed4e 100644
--- a/ivette/api/generated/kernel/properties/index.ts
+++ b/ivette/api/generated/kernel/properties/index.ts
@@ -225,7 +225,7 @@ export const alarmsTags: Server.GetRequest<null,tag[]>= alarmsTags_internal;
 /** Data for array rows [`status`](#status)  */
 export interface statusData {
   /** Entry identifier. */
-  key: Json.key<'#status'>;
+  key: Json.key<'#property'>;
   /** Full description */
   descr: string;
   /** Kind */
@@ -235,7 +235,7 @@ export interface statusData {
   /** Status */
   status: propStatus;
   /** Function */
-  function?: Json.key<'#fct'>;
+  fct?: Json.key<'#fct'>;
   /** Instruction */
   kinstr?: Json.key<'#stmt'>;
   /** Position */
@@ -251,12 +251,12 @@ export interface statusData {
 /** Loose decoder for `statusData` */
 export const jStatusData: Json.Loose<statusData> =
   Json.jObject({
-    key: Json.jFail(Json.jKey<'#status'>('#status'),'#status expected'),
+    key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'),
     descr: Json.jFail(Json.jString,'String expected'),
     kind: jPropKindSafe,
     names: Json.jList(Json.jString),
     status: jPropStatusSafe,
-    function: Json.jKey<'#fct'>('#fct'),
+    fct: Json.jKey<'#fct'>('#fct'),
     kinstr: Json.jKey<'#stmt'>('#stmt'),
     source: jSourceSafe,
     alarm: Json.jString,
@@ -271,8 +271,8 @@ export const jStatusDataSafe: Json.Safe<statusData> =
 /** Natural order for `statusData` */
 export const byStatusData: Compare.Order<statusData> =
   Compare.byFields
-    <{ key: Json.key<'#status'>, descr: string, kind: propKind,
-       names: string[], status: propStatus, function?: Json.key<'#fct'>,
+    <{ key: Json.key<'#property'>, descr: string, kind: propKind,
+       names: string[], status: propStatus, fct?: Json.key<'#fct'>,
        kinstr?: Json.key<'#stmt'>, source: source, alarm?: string,
        alarm_descr?: string, predicate?: string }>({
     key: Compare.string,
@@ -280,7 +280,7 @@ export const byStatusData: Compare.Order<statusData> =
     kind: byPropKind,
     names: Compare.array(Compare.string),
     status: byPropStatus,
-    function: Compare.defined(Compare.string),
+    fct: Compare.defined(Compare.string),
     kinstr: Compare.defined(Compare.string),
     source: bySource,
     alarm: Compare.defined(Compare.string),
@@ -304,7 +304,7 @@ export const reloadStatus: Server.GetRequest<null,null>= reloadStatus_internal;
 
 const fetchStatus_internal: Server.GetRequest<
   number,
-  { pending: number, updated: statusData[], removed: Json.key<'#status'>[],
+  { pending: number, updated: statusData[], removed: Json.key<'#property'>[],
     reload: boolean }
   > = {
   kind: Server.RqKind.GET,
@@ -313,18 +313,18 @@ const fetchStatus_internal: Server.GetRequest<
   output: Json.jObject({
             pending: Json.jFail(Json.jNumber,'Number expected'),
             updated: Json.jList(jStatusData),
-            removed: Json.jList(Json.jKey<'#status'>('#status')),
+            removed: Json.jList(Json.jKey<'#property'>('#property')),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
 };
 /** Data fetcher for array [`status`](#status)  */
 export const fetchStatus: Server.GetRequest<
   number,
-  { pending: number, updated: statusData[], removed: Json.key<'#status'>[],
+  { pending: number, updated: statusData[], removed: Json.key<'#property'>[],
     reload: boolean }
   >= fetchStatus_internal;
 
-const status_internal: State.Array<Json.key<'#status'>,statusData> = {
+const status_internal: State.Array<Json.key<'#property'>,statusData> = {
   name: 'kernel.properties.status',
   getkey: ((d:statusData) => d.key),
   signal: signalStatus,
@@ -333,6 +333,6 @@ const status_internal: State.Array<Json.key<'#status'>,statusData> = {
   order: byStatusData,
 };
 /** Status of Registered Properties */
-export const status: State.Array<Json.key<'#status'>,statusData> = status_internal;
+export const status: State.Array<Json.key<'#property'>,statusData> = status_internal;
 
 /* ------------------------------------- */
diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml
index d190a3b3e19a78816c2a97fe4adef1be20f3a98b..669d83168c2cd58d3536c88a00742bbf9864f187 100644
--- a/ivette/api/server_tsc.ml
+++ b/ivette/api/server_tsc.ml
@@ -375,10 +375,9 @@ let makeDeclaration fmt names d =
       self.name jtype js self.name;
 
 
-  | D_array { arr_key ; arr_kind } ->
+  | D_array { arr_key ; arr_kind = jkey } ->
     let data = Pkg.Derived.data self in
-    let jkey = (Pkg.Jkey arr_kind) in
-    let jrow = (Pkg.Jdata data) in
+    let jrow = Pkg.Jdata data in
     Format.fprintf fmt
       "@[<hv 2>const %s_internal: State.Array<@,%a,@,%a@,>@] = {@\n"
       self.name jtype jkey jtype jrow ;
diff --git a/ivette/src/frama-c/eva/Values.tsx b/ivette/src/frama-c/eva/Values.tsx
index 12de5e02e76db03216962de1d270a7f92761e6b9..798b64bd19ccc4ff763122d15402684ba8c0d508 100644
--- a/ivette/src/frama-c/eva/Values.tsx
+++ b/ivette/src/frama-c/eva/Values.tsx
@@ -218,7 +218,7 @@ function StackInfo() {
       focused === stmt && 'eva-focused',
     );
     const onClick = () => {
-      const location = { function: caller, marker: stmt };
+      const location = { fct: caller, marker: stmt };
       setSelection({ location });
     };
     return (
@@ -361,7 +361,7 @@ function TableCell(props: TableCellProps) {
   );
   const onClick = () => {
     if (probe) {
-      const location = { function: probe.fct, marker: probe.marker };
+      const location = { fct: probe.fct, marker: probe.marker };
       setSelection({ location });
       model.setSelectedRow(row);
     }
@@ -497,7 +497,7 @@ function ValuesPanel(props: ValuesPanelProps) {
   const [selection] = States.useSelection();
   React.useEffect(() => {
     const curr = selection?.current;
-    const fct = curr?.function;
+    const fct = curr?.fct;
     const marker = Ast.jMarker(curr?.marker);
     model.setLayout({ zoom, margin, fct, marker });
   });
diff --git a/ivette/src/frama-c/eva/stacks.ts b/ivette/src/frama-c/eva/stacks.ts
index 3583661f6b2dedd9764732f0d249fa667eb380b9..aef6e64d511431dd886116f03a89996a1dfb1f30 100644
--- a/ivette/src/frama-c/eva/stacks.ts
+++ b/ivette/src/frama-c/eva/stacks.ts
@@ -16,7 +16,7 @@ export type callstacks = Values.callstack[];
 export interface Callsite {
   callee: string;
   caller?: string;
-  stmt?: string;
+  stmt?: Ast.marker;
   rank?: number;
 }
 
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 3895ee4978f75af68bed38a3677e579510941174..377ab636464fc688519e4c6ef394a26f3bda3df9 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -15,6 +15,7 @@ import { Order } from 'dome/data/compare';
 import { GlobalState, useGlobalState } from 'dome/data/states';
 import { useModel } from 'dome/table/models';
 import { CompactModel } from 'dome/table/arrays';
+import * as Ast from 'frama-c/api/kernel/ast';
 import * as Server from './server';
 
 const PROJECT = new Dome.Event('frama-c.project');
@@ -445,22 +446,15 @@ export function useSyncArray<K, A>(
 // --- Selection
 // --------------------------------------------------------------------------
 
-type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> =
-  Partial<T> & U[keyof U];
-
-export interface FullLocation {
-  /** Function name. */
-  readonly function: string;
-  /** Marker identifier. */
-  readonly marker: string;
-}
-
 /** An AST location.
  *
  *  Properties [[function]] and [[marker]] are optional,
  *  but at least one of the two must be set.
  */
-export type Location = AtLeastOne<FullLocation>;
+export type Location = {
+  fct?: string;
+  marker?: Ast.marker;
+};
 
 export interface HistorySelection {
   /** Previous locations with respect to the [[current]] one. */
@@ -554,7 +548,7 @@ function isNthSelect(a: SelectionActions): a is NthSelect {
 /** Update selection to the given location. */
 function selectLocation(s: Selection, location: Location): Selection {
   const [prevSelections, nextSelections] =
-    s.current && s.current.function !== location.function ?
+    s.current && s.current.fct !== location.fct ?
       [[s.current, ...s.history.prevSelections], []] :
       [s.history.prevSelections, s.history.nextSelections];
   return {
diff --git a/ivette/src/renderer/ASTinfo.tsx b/ivette/src/renderer/ASTinfo.tsx
index be2aa17a99d70cb07f0ab23ac1a61174ac880922..4ad40c6cfb0f6f7a11ea12881388d5a2e20da908 100644
--- a/ivette/src/renderer/ASTinfo.tsx
+++ b/ivette/src/renderer/ASTinfo.tsx
@@ -33,7 +33,7 @@ const ASTinfo = () => {
   // Callbacks
   function onTextSelection(id: string) {
     // For now, the only markers are functions.
-    const location = { function: id };
+    const location = { fct: id };
     updateSelection({ location });
   }
 
diff --git a/ivette/src/renderer/ASTview.tsx b/ivette/src/renderer/ASTview.tsx
index 8583af381634c5a90bebcf4e82ac79ff56515e73..c5f941f18664276e55883500a9ef0933affe02b0 100644
--- a/ivette/src/renderer/ASTview.tsx
+++ b/ivette/src/renderer/ASTview.tsx
@@ -9,11 +9,10 @@ import * as States from 'frama-c/states';
 import * as Utils from 'frama-c/utils';
 
 import * as Dome from 'dome';
-import * as Json from 'dome/data/json';
 import { RichTextBuffer } from 'dome/text/buffers';
 import { Text } from 'dome/text/editors';
 import { Component, TitleBar } from 'frama-c/LabViews';
-import * as AST from 'frama-c/api/kernel/ast';
+import * as Ast from 'frama-c/api/kernel/ast';
 import * as Properties from 'frama-c/api/kernel/properties';
 import { getCallers, getDeadCode } from 'frama-c/api/plugins/eva/general';
 import { getWritesLval, getReadsLval } from 'frama-c/api/plugins/studia/studia';
@@ -38,7 +37,7 @@ async function loadAST(
     buffer.log('// Loading', theFunction, '…');
     (async () => {
       try {
-        const data = await Server.send(AST.printFunction, theFunction);
+        const data = await Server.send(Ast.printFunction, theFunction);
         buffer.clear();
         if (!data) {
           buffer.log('// No code for function', theFunction);
@@ -63,7 +62,7 @@ async function loadAST(
 async function functionCallers(functionName: string) {
   try {
     const data = await Server.send(getCallers, functionName);
-    const locations = data.map(([fct, marker]) => ({ function: fct, marker }));
+    const locations = data.map(([fct, marker]) => ({ fct, marker }));
     return locations;
   } catch (err) {
     D.error(`Fail to retrieve callers of function '${functionName}':`, err);
@@ -79,12 +78,12 @@ type access = 'Reads' | 'Writes';
 
 async function studia(
   marker: string,
-  info: AST.markerInfoData,
+  info: Ast.markerInfoData,
   kind: access,
 ) {
   const request = kind === 'Reads' ? getReadsLval : getWritesLval;
   const data = await Server.send(request, marker);
-  const locations = data.direct.map(([f, m]) => ({ function: f, marker: m }));
+  const locations = data.direct.map(([f, m]) => ({ fct: f, marker: m }));
   const lval = info.name;
   if (locations.length > 0) {
     const name = `${kind} of ${lval}`;
@@ -139,7 +138,7 @@ const ASTview = () => {
   const printed = React.useRef<string | undefined>();
   const [selection, updateSelection] = States.useSelection();
   const multipleSelections = selection?.multiple.allSelections;
-  const theFunction = selection?.current?.function;
+  const theFunction = selection?.current?.fct;
   const theMarker = selection?.current?.marker;
   const { buttons: themeButtons, theme, fontSize, wrapText } =
     Preferences.useThemeButtons({
@@ -150,7 +149,7 @@ const ASTview = () => {
       disabled: !theFunction,
     });
 
-  const markersInfo = States.useSyncArray(AST.markerInfo);
+  const markersInfo = States.useSyncArray(Ast.markerInfo);
   const deadCode = States.useRequest(getDeadCode, theFunction);
   const propertyStatus = States.useSyncArray(Properties.status).getArray();
   const statusDict = States.useTags(Properties.propStatusTags);
@@ -158,7 +157,7 @@ const ASTview = () => {
   const setBullets = React.useCallback(() => {
     if (theFunction) {
       propertyStatus.forEach((prop) => {
-        if (prop.function === theFunction) {
+        if (prop.fct === theFunction) {
           const status = statusDict.get(prop.status);
           if (status) {
             const bullet = makeBullet(status);
@@ -206,26 +205,26 @@ const ASTview = () => {
     if (theMarker) buffer.scroll(theMarker);
   }, [buffer, theMarker]);
 
-  function onTextSelection(id: string) {
+  function onSelection(markerId: string) {
     if (selection.current) {
-      const location = { ...selection.current, marker: id };
+      const { fct } = selection.current;
+      const location: States.Location = { fct, marker: Ast.jMarker(markerId) };
       updateSelection({ location });
     }
   }
 
-  async function onContextMenu(id: string) {
+  async function onContextMenu(markerId: string) {
     const items = [];
-    const markerId = (id as Json.key<'#markerInfo'>);
     const selectedMarkerInfo = markersInfo.getData(markerId);
     if (selectedMarkerInfo?.var === 'function') {
       if (selectedMarkerInfo.kind === 'declaration') {
         const name = selectedMarkerInfo?.name;
         if (name) {
           const locations = await functionCallers(name);
-          const locationsByFunction = _.groupBy(locations, (e) => e.function);
+          const locationsByFunction = _.groupBy(locations, (e) => e.fct);
           _.forEach(locationsByFunction,
             (e) => {
-              const callerName = e[0].function;
+              const callerName = e[0].fct;
               items.push({
                 label:
                   `Go to caller ${callerName} ` +
@@ -233,7 +232,7 @@ const ASTview = () => {
                 onClick: () => updateSelection({
                   name: `Call sites of function ${name}`,
                   locations,
-                  index: locations.findIndex((l) => l.function === callerName),
+                  index: locations.findIndex((l) => l.fct === callerName),
                 }),
               });
             });
@@ -242,7 +241,7 @@ const ASTview = () => {
         items.push({
           label: `Go to definition of ${selectedMarkerInfo.name}`,
           onClick: () => {
-            const location = { function: selectedMarkerInfo.name };
+            const location = { fct: selectedMarkerInfo.name };
             updateSelection({ location });
           },
         });
@@ -252,7 +251,11 @@ const ASTview = () => {
       || selectedMarkerInfo?.var === 'variable';
     function onClick(kind: access) {
       if (selectedMarkerInfo)
-        studia(markerId, selectedMarkerInfo, kind).then(updateSelection);
+        studia(
+          markerId,
+          selectedMarkerInfo,
+          kind,
+        ).then(updateSelection);
     }
     items.push({
       label: 'Studia: select writes',
@@ -281,7 +284,7 @@ const ASTview = () => {
         fontSize={fontSize}
         lineWrapping={wrapText}
         selection={theMarker}
-        onSelection={onTextSelection}
+        onSelection={onSelection}
         onContextMenu={onContextMenu}
         gutters={['bullet']}
         readOnly
diff --git a/ivette/src/renderer/Globals.tsx b/ivette/src/renderer/Globals.tsx
index 27d21bc47181ee8f530e98abf2c209324240992b..0a4d754b4fdcfb12cd00740af485edd0ae92275e 100644
--- a/ivette/src/renderer/Globals.tsx
+++ b/ivette/src/renderer/Globals.tsx
@@ -23,7 +23,7 @@ const makeHint = (fct: functionsData): GlobalHint => ({
   id: fct.key,
   label: fct.name,
   title: fct.signature,
-  value: { function: fct.name },
+  value: { fct: fct.name },
 });
 
 export function useHints(): [GlobalHint[], (pattern: string) => void] {
@@ -101,12 +101,12 @@ export default () => {
 
   function isSelected(fct: functionsData) {
     return multipleSelection?.allSelections.some(
-      (l) => fct.name === l?.function
+      (l) => fct.name === l?.fct
     );
   }
 
   // Currently selected function.
-  const current: undefined | string = selection?.current?.function;
+  const current: undefined | string = selection?.current?.fct;
 
   function showFunction(fct: functionsData) {
     const visible =
@@ -119,7 +119,7 @@ export default () => {
   }
 
   function onSelection(name: string) {
-    updateSelection({ location: { function: name } });
+    updateSelection({ location: { fct: name } });
   }
 
   async function onContextMenu() {
diff --git a/ivette/src/renderer/Properties.tsx b/ivette/src/renderer/Properties.tsx
index 89737980d9c4855cf01eed52d767aef811f418df..9189a9263631ba5fac55ce5b5ff1b47227e6d4f1 100644
--- a/ivette/src/renderer/Properties.tsx
+++ b/ivette/src/renderer/Properties.tsx
@@ -235,7 +235,7 @@ const byStatus =
 
 const byProperty: Compare.ByFields<Property> = {
   status: byStatus,
-  function: Compare.defined(Compare.alpha),
+  fct: Compare.defined(Compare.alpha),
   source: bySource,
   kind: Compare.structural,
   alarm: Compare.defined(Compare.alpha),
@@ -270,7 +270,7 @@ class PropertyModel extends Arrays.CompactModel<Json.key<'#status'>, Property> {
   }
 
   filterItem(prop: Property) {
-    const kf = prop.function;
+    const kf = prop.fct;
     const cf = this.filterFun;
     const filteringFun = cf && filter('currentFunction');
     const filterFunction = filteringFun ? kf === cf : true;
@@ -477,15 +477,14 @@ const RenderTable = () => {
     model.reload();
   }, [model, data]);
 
-  const [selection, updateSelection] =
-    States.useSelection();
+  const [selection, updateSelection] = States.useSelection();
 
   const [showFilter, flipFilter] =
     Dome.useFlipSettings('ivette.properties.showFilter');
 
   // Updating the filter
   Dome.useEvent(Reload, model.reload);
-  const selectedFunction = selection?.current?.function;
+  const selectedFunction = selection?.current?.fct;
   React.useEffect(() => {
     model.setFilterFunction(selectedFunction);
   }, [model, selectedFunction]);
@@ -493,8 +492,8 @@ const RenderTable = () => {
   // Callbacks
 
   const onPropertySelection = React.useCallback(
-    ({ key: propKey, function: fct }: Property) => {
-      const location = { function: fct, marker: propKey };
+    ({ key: marker, fct }: Property) => {
+      const location = { fct, marker };
       updateSelection({ location });
     }, [updateSelection],
   );
diff --git a/ivette/src/renderer/SourceCode.tsx b/ivette/src/renderer/SourceCode.tsx
index 0c9f8a7dfa42d7a626938d1fe10f5d24016c76a8..aa1ca31d7984a27de13b2a886f9231e5afe1158b 100644
--- a/ivette/src/renderer/SourceCode.tsx
+++ b/ivette/src/renderer/SourceCode.tsx
@@ -7,7 +7,6 @@ import * as States from 'frama-c/states';
 
 import * as Dome from 'dome';
 import { readFile } from 'dome/system';
-import * as Json from 'dome/data/json';
 import { RichTextBuffer } from 'dome/text/buffers';
 import { Text } from 'dome/text/editors';
 import { Component, TitleBar } from 'frama-c/LabViews';
@@ -37,7 +36,7 @@ const SourceCode = () => {
   // Hooks
   const buffer = React.useMemo(() => new RichTextBuffer(), []);
   const [selection] = States.useSelection();
-  const theFunction = selection?.current?.function;
+  const theFunction = selection?.current?.fct;
   const theMarker = selection?.current?.marker;
   const { buttons: themeButtons, theme, fontSize, wrapText } =
     Preferences.useThemeButtons({
@@ -72,10 +71,8 @@ const SourceCode = () => {
     }
     // Actual source code loading upon function or marker update.
     const sloc =
-      /* Non-empty [selection] has defined either marker or function: we give
-         precedence to marker as it provides more precise source location. */
-      (theMarker &&
-        markersInfo.getData(theMarker as Json.key<'#markerInfo'>)?.sloc)
+      /* markers have more precise source location */
+      (theMarker && markersInfo.getData(theMarker)?.sloc)
       ??
       (theFunction && functionsData.find((e) => e.name === theFunction)?.sloc);
     if (sloc) {
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index a8e380889208883e6e45eff039c4180a26dd898c..b707805c9980c3ac1b8d6e653b9158c3933282ab 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -206,7 +206,7 @@ struct
       ~package
       ~name:"markerInfo"
       ~descr:(Md.plain "Marker informations")
-      ~key:snd
+      ~key:snd ~keyType:Jstring
       ~iter model
 
   let create_tag = function
diff --git a/src/plugins/server/kernel_properties.ml b/src/plugins/server/kernel_properties.ml
index 511c5299a0e354b86bef51f466c5d02b060e0eef..4f09c05dab339a6a5f2f94916f04dd81cdedea4f 100644
--- a/src/plugins/server/kernel_properties.ml
+++ b/src/plugins/server/kernel_properties.ml
@@ -281,7 +281,7 @@ let () = States.column model ~name:"status"
     ~data:(module PropStatus)
     ~get:(Property_status.Feedback.get)
 
-let () = States.column model ~name:"function"
+let () = States.column model ~name:"fct"
     ~descr:(Md.plain "Function")
     ~data:(module Joption(Kf)) ~get:Property.get_kf
 
@@ -330,6 +330,7 @@ let array =
     ~name:"status"
     ~descr:(Md.plain "Status of Registered Properties")
     ~key:(fun ip -> Kernel_ast.Marker.create (PIP ip))
+    ~keyType:Kernel_ast.Marker.jproperty
     ~iter
     ~add_update_hook
     ~add_remove_hook
diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml
index 309cae632565703288b5cc95ca1a5793215cfba5..bb87b1da3d58d915060b0455fa705ae855e78eba 100644
--- a/src/plugins/server/package.ml
+++ b/src/plugins/server/package.ml
@@ -208,7 +208,7 @@ type requestInfo = {
 
 type arrayInfo = {
   arr_key: string;
-  arr_kind: string;
+  arr_kind: jtype;
 }
 
 type declKindInfo =
diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli
index 952f0dd05659e32932bce624cb57c19fcc2e8741..30075f6243c419aca7d1e4e98ba70462c1704d1d 100644
--- a/src/plugins/server/package.mli
+++ b/src/plugins/server/package.mli
@@ -72,7 +72,7 @@ type requestInfo = {
 
 type arrayInfo = {
   arr_key: string;
-  arr_kind: string;
+  arr_kind: jtype;
 }
 
 type declKindInfo =
diff --git a/src/plugins/server/states.ml b/src/plugins/server/states.ml
index f9ae51a5b8acb166d074e7b2dc88b1624e90c1b1..52a682f2bc7b854e86c8435201fa231ebcc3c4e6 100644
--- a/src/plugins/server/states.ml
+++ b/src/plugins/server/states.ml
@@ -293,9 +293,14 @@ let fetch array n =
 (* --- Signature Registry                                                 --- *)
 (* -------------------------------------------------------------------------- *)
 
+let rec is_keyType = function
+  | Package.Junion js -> List.for_all is_keyType js
+  | Jstring | Jalpha | Jkey _ | Jtag _ -> true
+  | _ -> false
+
 let register_array ~package ~name ~descr ~key
     ?(keyName="key")
-    ?(keyKind=name)
+    ?(keyType=Package.Jkey name)
     ~(iter : 'a callback)
     ?(add_update_hook : 'a callback option)
     ?(add_remove_hook : 'a callback option)
@@ -304,15 +309,24 @@ let register_array ~package ~name ~descr ~key
   let open Markdown in
   let href = link ~name () in
   let columns = List.rev !model in
-  if List.exists (fun (fd,_) -> fd.Package.fd_name = keyName) columns then
-    raise (Invalid_argument "States.array: key name overrides column name") ;
+  begin
+    if List.exists (fun (fd,_) -> fd.Package.fd_name = keyName) columns then
+      raise (Invalid_argument (
+          Printf.sprintf "States.array(%S) : invalid key %S"
+            name keyName
+        ));
+    if not (is_keyType keyType) then
+      raise (Invalid_argument (
+          Printf.sprintf "States.array(%S): invalid key type" name
+        ));
+  end ;
   let fields = Package.{
       fd_name = keyName ;
-      fd_type = Jkey keyKind ;
+      fd_type = keyType ;
       fd_descr = plain "Entry identifier." ;
     } :: List.map fst columns in
   let id = Package.declare_id ~package:package ~name:name ~descr
-      (D_array { arr_key = keyName ; arr_kind = keyKind }) in
+      (D_array { arr_key = keyName ; arr_kind = keyType }) in
   let signal = Request.signal
       ~package ~name:(Package.Derived.signal id).name
       ~descr:(plain "Signal for array" @ href) in
@@ -331,7 +345,7 @@ let register_array ~package ~name ~descr ~key
   let signature = Request.signature ~input:(module Jint) () in
   let module Jkeys = Jlist(struct
       include Jstring
-      let jtype = Package.Jkey keyKind
+      let jtype = keyType
     end) in
   let module Jrows = Jlist (struct
       include Jany
diff --git a/src/plugins/server/states.mli b/src/plugins/server/states.mli
index a75c6c76c8776b067e39b4544c66198d3424fe89..1f38038f83ee1d2b4ea80a1fb1704119e9bf9021 100644
--- a/src/plugins/server/states.mli
+++ b/src/plugins/server/states.mli
@@ -136,7 +136,7 @@ val register_array :
   descr:Markdown.text ->
   key:('a -> string) ->
   ?keyName:string ->
-  ?keyKind:string ->
+  ?keyType:jtype ->
   iter:('a callback) ->
   ?add_update_hook:('a callback) ->
   ?add_remove_hook:('a callback) ->