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
相关产品推荐
相关产品推荐

