You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ada 95程序在Ada 2012下实例化泛型包的变体记录访问子类型报错及适配

问题背景

使用Ada 2012编译器编译基于Ada 95编写的程序时,在实例化泛型包Garbage_Collector环节触发类型匹配错误,编译器输出如下报错:

prolog.adb:27:15: 实参的指定类型与形参"Link"的指定类型不匹配
prolog.adb:27:15: 实例化中止

曾尝试将A_Term的定义修改为type A_Term is access A_Node;,修改后泛型包虽然可以成功实例化,但其余原有代码全部触发类型不匹配报错。
涉及的问题代码来源于斯坦福大学开发的Prolog开源模块。

可复现的问题代码
procedure Prolog is

   generic
      type Item is limited private;
      type Link is access Item;
   package Garbage_Collector is
      procedure Get (L : in out Link) is null;
   end Garbage_Collector;

   type Node_Tag is (A, B);

   type Node (Tag : Node_Tag);
   type Term is access Node;

   type Node (Tag : Node_Tag) is
      record
         case Tag is
            when A => null;
            when B => null;
         end case;
      end record;

   subtype A_Node is Node (A);
   subtype A_Term is Term (A);
   package Gc_A is new Garbage_Collector
     (Item => A_Node,
      Link => A_Term);

   T : Term;
begin
   Gc_A.Get (T);
end Prolog;
Ada 95到Ada 2012的相关规则变化

泛型形参匹配规则在Ada 2012版本中做了严格收紧,核心影响包括:

  • 对于形式为type <访问名> is access <元素类型>;的泛型访问类形参,要求传入的实参必须是无判别式约束的、独立的命名访问类型,且指向的元素类型与形参指定的元素类型严格匹配
  • Ada 95版本宽松允许带判别式约束的访问子类型(如本例中subtype A_Term is Term (A);)作为上述泛型形参的实参;Ada 2012中这类带约束的访问子类型不再满足匹配要求,直接触发实例化失败
  • 强类型规则的一致性校验在Ada 2012中更严格:独立定义的访问类型哪怕指向兼容的元素类型,也与原有访问类型属于完全不同的命名类型,不存在隐式兼容关系。这也是直接重定义A_Term为独立访问类型后,原有代码大面积报错的核心原因
适配Ada 2012的代码调整方案

无需重定义独立的访问类型,仅需修改泛型包的形参声明,即可兼容原有带判别式约束的访问子类型,同时不破坏原有代码类型兼容性:

  • 将泛型中type Link is access Item;的形参定义修改为type Link is access Item'Base;
  • 该修改将泛型形参匹配范围扩展到所有指向Item及其任意约束子类的访问类型,既可以匹配A_Term这类带判别式约束的访问子类型,又不会影响原有Term类型的传参、赋值逻辑
调整后的可运行示例代码
procedure Prolog is

   generic
      type Item is limited private;
      -- 仅需修改这一行形参定义即可适配Ada 2012规则
      type Link is access Item'Base;
   package Garbage_Collector is
      procedure Get (L : in out Link) is null;
   end Garbage_Collector;

   type Node_Tag is (A, B);

   type Node (Tag : Node_Tag);
   type Term is access Node;

   type Node (Tag : Node_Tag) is
      record
         case Tag is
            when A => null;
            when B => null;
         end case;
      end record;

   subtype A_Node is Node (A);
   subtype A_Term is Term (A);
   package Gc_A is new Garbage_Collector
     (Item => A_Node,
      Link => A_Term);

   T : Term;
begin
   Gc_A.Get (T);
end Prolog;

注意:不要通过重新定义独立访问类型的方式绕过泛型匹配错误,这类操作会彻底切断新旧访问类型之间的兼容性,导致原有依赖Term类型的所有逻辑报错。


内容的提问来源于stack exchange,提问作者Jesper Quorning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 15:24:09