blob: 396f616cbf13ef30c21a823ce7cd3e2dc6d7ec79 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ T Y P E --
-- --
-- B o d y --
-- --
-- Copyright (C) 1992-2021, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING3. If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Aspects; use Aspects;
with Atree; use Atree;
with Alloc;
with Debug; use Debug;
with Einfo; use Einfo;
with Einfo.Entities; use Einfo.Entities;
with Einfo.Utils; use Einfo.Utils;
with Elists; use Elists;
with Nlists; use Nlists;
with Errout; use Errout;
with Lib; use Lib;
with Namet; use Namet;
with Opt; use Opt;
with Output; use Output;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch12; use Sem_Ch12;
with Sem_Disp; use Sem_Disp;
with Sem_Dist; use Sem_Dist;
with Sem_Util; use Sem_Util;
with Stand; use Stand;
with Sinfo; use Sinfo;
with Sinfo.Nodes; use Sinfo.Nodes;
with Sinfo.Utils; use Sinfo.Utils;
with Snames; use Snames;
with Table;
with Treepr; use Treepr;
with Uintp; use Uintp;
with GNAT.HTable; use GNAT.HTable;
package body Sem_Type is
---------------------
-- Data Structures --
---------------------
-- The following data structures establish a mapping between nodes and
-- their interpretations. An overloaded node has an entry in Interp_Map,
-- which in turn contains a pointer into the All_Interp array. The
-- interpretations of a given node are contiguous in All_Interp. Each set
-- of interpretations is terminated with the marker No_Interp.
-- Interp_Map All_Interp
-- +-----+ +--------+
-- | | --->|interp1 |
-- |_____| | |interp2 |
-- |index|---------| |nointerp|
-- |-----| | |
-- | | | |
-- +-----+ +--------+
-- This scheme does not currently reclaim interpretations. In principle,
-- after a unit is compiled, all overloadings have been resolved, and the
-- candidate interpretations should be deleted. This should be easier
-- now than with the previous scheme???
package All_Interp is new Table.Table (
Table_Component_Type => Interp,
Table_Index_Type => Interp_Index,
Table_Low_Bound => 0,
Table_Initial => Alloc.All_Interp_Initial,
Table_Increment => Alloc.All_Interp_Increment,
Table_Name => "All_Interp");
Header_Max : constant := 3079;
-- The number of hash buckets; an arbitrary prime number
subtype Header_Num is Integer range 0 .. Header_Max - 1;
function Hash (N : Node_Id) return Header_Num;
-- A trivial hashing function for nodes, used to insert an overloaded
-- node into the Interp_Map table.
package Interp_Map is new Simple_HTable
(Header_Num => Header_Num,
Element => Interp_Index,
No_Element => -1,
Key => Node_Id,
Hash => Hash,
Equal => "=");
Last_Overloaded : Node_Id := Empty;
-- Overloaded node after initializing a new collection of intepretation
-------------------------------------
-- Handling of Overload Resolution --
-------------------------------------
-- Overload resolution uses two passes over the syntax tree of a complete
-- context. In the first, bottom-up pass, the types of actuals in calls
-- are used to resolve possibly overloaded subprogram and operator names.
-- In the second top-down pass, the type of the context (for example the
-- condition in a while statement) is used to resolve a possibly ambiguous
-- call, and the unique subprogram name in turn imposes a specific context
-- on each of its actuals.
-- Most expressions are in fact unambiguous, and the bottom-up pass is
-- sufficient to resolve most everything. To simplify the common case,
-- names and expressions carry a flag Is_Overloaded to indicate whether
-- they have more than one interpretation. If the flag is off, then each
-- name has already a unique meaning and type, and the bottom-up pass is
-- sufficient (and much simpler).
--------------------------
-- Operator Overloading --
--------------------------
-- The visibility of operators is handled differently from that of other
-- entities. We do not introduce explicit versions of primitive operators
-- for each type definition. As a result, there is only one entity
-- corresponding to predefined addition on all numeric types, etc. The
-- back end resolves predefined operators according to their type. The
-- visibility of primitive operations then reduces to the visibility of the
-- resulting type: (a + b) is a legal interpretation of some primitive
-- operator + if the type of the result (which must also be the type of a
-- and b) is directly visible (either immediately visible or use-visible).
-- User-defined operators are treated like other functions, but the
-- visibility of these user-defined operations must be special-cased
-- to determine whether they hide or are hidden by predefined operators.
-- The form P."+" (x, y) requires additional handling.
-- Concatenation is treated more conventionally: for every one-dimensional
-- array type we introduce a explicit concatenation operator. This is
-- necessary to handle the case of (element & element => array) which
-- cannot be handled conveniently if there is no explicit instance of
-- resulting type of the operation.
-----------------------
-- Local Subprograms --
-----------------------
procedure All_Overloads;
pragma Warnings (Off, All_Overloads);
-- Debugging procedure: list full contents of Overloads table
function Binary_Op_Interp_Has_Abstract_Op
(N : Node_Id;
E : Entity_Id) return Entity_Id;
-- Given the node and entity of a binary operator, determine whether the
-- actuals of E contain an abstract interpretation with regards to the
-- types of their corresponding formals. Return the abstract operation or
-- Empty.
function Function_Interp_Has_Abstract_Op
(N : Node_Id;
E : Entity_Id) return Entity_Id;
-- Given the node and entity of a function call, determine whether the
-- actuals of E contain an abstract interpretation with regards to the
-- types of their corresponding formals. Return the abstract operation or
-- Empty.
function Has_Abstract_Op
(N : Node_Id;
Typ : Entity_Id) return Entity_Id;
-- Subsidiary routine to Binary_Op_Interp_Has_Abstract_Op and Function_
-- Interp_Has_Abstract_Op. Determine whether an overloaded node has an
-- abstract interpretation which yields type Typ.
procedure New_Interps (N : Node_Id);
-- Initialize collection of interpretations for the given node, which is
-- either an overloaded entity, or an operation whose arguments have
-- multiple interpretations. Interpretations can be added to only one
-- node at a time.
function Specific_Type (Typ_1, Typ_2 : Entity_Id) return Entity_Id;
-- If Typ_1 and Typ_2 are compatible, return the one that is not universal
-- or is not a "class" type (any_character, etc).
--------------------
-- Add_One_Interp --
--------------------
procedure Add_One_Interp
(N : Node_Id;
E : Entity_Id;
T : Entity_Id;
Opnd_Type : Entity_Id := Empty)
is
Vis_Type : Entity_Id;
procedure Add_Entry (Name : Entity_Id; Typ : Entity_Id);
-- Add one interpretation to an overloaded node. Add a new entry if
-- not hidden by previous one, and remove previous one if hidden by
-- new one.
function Is_Universal_Operation (Op : Entity_Id) return Boolean;
-- True if the entity is a predefined operator and the operands have
-- a universal Interpretation.
---------------
-- Add_Entry --
---------------
procedure Add_Entry (Name : Entity_Id; Typ : Entity_Id) is
Abstr_Op : Entity_Id := Empty;
I : Interp_Index;
It : Interp;
-- Start of processing for Add_Entry
begin
-- Find out whether the new entry references interpretations that
-- are abstract or disabled by abstract operators.
if Ada_Version >= Ada_2005 then
if Nkind (N) in N_Binary_Op then
Abstr_Op := Binary_Op_Interp_Has_Abstract_Op (N, Name);
elsif Nkind (N) = N_Function_Call then
Abstr_Op := Function_Interp_Has_Abstract_Op (N, Name);
end if;
end if;
Get_First_Interp (N, I, It);
while Present (It.Nam) loop
-- Avoid making duplicate entries in overloads
if Name = It.Nam
and then Base_Type (It.Typ) = Base_Type (T)
then
return;
-- A user-defined subprogram hides another declared at an outer
-- level, or one that is use-visible. So return if previous
-- definition hides new one (which is either in an outer
-- scope, or use-visible). Note that for functions use-visible
-- is the same as potentially use-visible. If new one hides
-- previous one, replace entry in table of interpretations.
-- If this is a universal operation, retain the operator in case
-- preference rule applies.
elsif ((Ekind (Name) in E_Function | E_Procedure
and then Ekind (Name) = Ekind (It.Nam))
or else (Ekind (Name) = E_Operator
and then Ekind (It.Nam) = E_Function))
and then Is_Immediately_Visible (It.Nam)
and then Type_Conformant (Name, It.Nam)
and then Base_Type (It.Typ) = Base_Type (T)
then
if Is_Universal_Operation (Name) then
exit;
-- If node is an operator symbol, we have no actuals with
-- which to check hiding, and this is done in full in the
-- caller (Analyze_Subprogram_Renaming) so we include the
-- predefined operator in any case.
elsif Nkind (N) = N_Operator_Symbol
or else
(Nkind (N) = N_Expanded_Name
and then Nkind (Selector_Name (N)) = N_Operator_Symbol)
then
exit;
elsif not In_Open_Scopes (Scope (Name))
or else Scope_Depth (Scope (Name)) <=
Scope_Depth (Scope (It.Nam))
then
-- If ambiguity within instance, and entity is not an
-- implicit operation, save for later disambiguation.
if Scope (Name) = Scope (It.Nam)
and then not Is_Inherited_Operation (Name)
and then In_Instance
then
exit;
else
return;
end if;
else
All_Interp.Table (I).Nam := Name;
return;
end if;
-- Otherwise keep going
else
Get_Next_Interp (I, It);
end if;
end loop;
All_Interp.Table (All_Interp.Last) := (Name, Typ, Abstr_Op);
All_Interp.Append (No_Interp);
end Add_Entry;
----------------------------
-- Is_Universal_Operation --
----------------------------
function Is_Universal_Operation (Op : Entity_Id) return Boolean is
Arg : Node_Id;
begin
if Ekind (Op) /= E_Operator then
return False;
elsif Nkind (N) in N_Binary_Op then
if Present (Universal_Interpretation (Left_Opnd (N)))
and then Present (Universal_Interpretation (Right_Opnd (N)))
then
return True;
elsif Nkind (N) in N_Op_Eq | N_Op_Ne
and then
(Is_Anonymous_Access_Type (Etype (Left_Opnd (N)))
or else Is_Anonymous_Access_Type (Etype (Right_Opnd (N))))
then
return True;
else
return False;
end if;
elsif Nkind (N) in N_Unary_Op then
return Present (Universal_Interpretation (Right_Opnd (N)));
elsif Nkind (N) = N_Function_Call then
Arg := First_Actual (N);
while Present (Arg) loop
if No (Universal_Interpretation (Arg)) then
return False;
end if;
Next_Actual (Arg);
end loop;
return True;
else
return False;
end if;
end Is_Universal_Operation;
-- Start of processing for Add_One_Interp
begin
-- If the interpretation is a predefined operator, verify that the
-- result type is visible, or that the entity has already been
-- resolved (case of an instantiation node that refers to a predefined
-- operation, or an internally generated operator node, or an operator
-- given as an expanded name). If the operator is a comparison or
-- equality, it is the type of the operand that matters to determine
-- whether the operator is visible. In an instance, the check is not
-- performed, given that the operator was visible in the generic.
if Ekind (E) = E_Operator then
if Present (Opnd_Type) then
Vis_Type := Opnd_Type;
else
Vis_Type := Base_Type (T);
end if;
if In_Open_Scopes (Scope (Vis_Type))
or else Is_Potentially_Use_Visible (Vis_Type)
or else In_Use (Vis_Type)
or else (In_Use (Scope (Vis_Type))
and then not Is_Hidden (Vis_Type))
or else Nkind (N) = N_Expanded_Name
or else (Nkind (N) in N_Op and then E = Entity (N))
or else (In_Instance or else In_Inlined_Body)
or else Is_Anonymous_Access_Type (Vis_Type)
then
null;
-- If the node is given in functional notation and the prefix
-- is an expanded name, then the operator is visible if the
-- prefix is the scope of the result type as well. If the
-- operator is (implicitly) defined in an extension of system,
-- it is know to be valid (see Defined_In_Scope, sem_ch4.adb).
elsif Nkind (N) = N_Function_Call
and then Nkind (Name (N)) = N_Expanded_Name
and then (Entity (Prefix (Name (N))) = Scope (Base_Type (T))
or else Entity (Prefix (Name (N))) = Scope (Vis_Type)
or else Scope (Vis_Type) = System_Aux_Id)
then
null;
-- Save type for subsequent error message, in case no other
-- interpretation is found.
else
Candidate_Type := Vis_Type;
return;
end if;
-- In an instance, an abstract non-dispatching operation cannot be a
-- candidate interpretation, because it could not have been one in the
-- generic (it may be a spurious overloading in the instance).
elsif In_Instance
and then Is_Overloadable (E)
and then Is_Abstract_Subprogram (E)
and then not Is_Dispatching_Operation (E)
then
return;
-- An inherited interface operation that is implemented by some derived
-- type does not participate in overload resolution, only the
-- implementation operation does.
elsif Is_Hidden (E)
and then Is_Subprogram (E)
and then Present (Interface_Alias (E))
then
-- Ada 2005 (AI-251): If this primitive operation corresponds with
-- an immediate ancestor interface there is no need to add it to the
-- list of interpretations. The corresponding aliased primitive is
-- also in this list of primitive operations and will be used instead
-- because otherwise we have a dummy ambiguity between the two
-- subprograms which are in fact the same.
if not Is_Ancestor
(Find_Dispatching_Type (Interface_Alias (E)),
Find_Dispatching_Type (E))
then
Add_One_Interp (N, Interface_Alias (E), T);
end if;
return;
-- Calling stubs for an RACW operation never participate in resolution,
-- they are executed only through dispatching calls.
elsif Is_RACW_Stub_Type_Operation (E) then
return;
end if;
-- If this is the first interpretation of N, N has type Any_Type.
-- In that case place the new type on the node. If one interpretation
-- already exists, indicate that the node is overloaded, and store
-- both the previous and the new interpretation in All_Interp. If
-- this is a later interpretation, just add it to the set.
if Etype (N) = Any_Type then
if Is_Type (E) then
Set_Etype (N, T);
else
-- Record both the operator or subprogram name, and its type
if Nkind (N) in N_Op or else Is_Entity_Name (N) then
Set_Entity (N, E);
end if;
Set_Etype (N, T);
end if;
-- Either there is no current interpretation in the table for any
-- node or the interpretation that is present is for a different
-- node. In both cases add a new interpretation to the table.
elsif No (Last_Overloaded)
or else
(Last_Overloaded /= N
and then not Is_Overloaded (N))
then
New_Interps (N);
if (Nkind (N) in N_Op or else Is_Entity_Name (N))
and then Present (Entity (N))
then
Add_Entry (Entity (N), Etype (N));
elsif Nkind (N) in N_Subprogram_Call
and then Is_Entity_Name (Name (N))
then
Add_Entry (Entity (Name (N)), Etype (N));
-- If this is an indirect call there will be no name associated
-- with the previous entry. To make diagnostics clearer, save
-- Subprogram_Type of first interpretation, so that the error will
-- point to the anonymous access to subprogram, not to the result
-- type of the call itself.
elsif (Nkind (N)) = N_Function_Call
and then Nkind (Name (N)) = N_Explicit_Dereference
and then Is_Overloaded (Name (N))
then
declare
It : Interp;
Itn : Interp_Index;
pragma Warnings (Off, Itn);
begin
Get_First_Interp (Name (N), Itn, It);
Add_Entry (It.Nam, Etype (N));
end;
else
-- Overloaded prefix in indexed or selected component, or call
-- whose name is an expression or another call.
Add_Entry (Etype (N), Etype (N));
end if;
Add_Entry (E, T);
else
Add_Entry (E, T);
end if;
end Add_One_Interp;
-------------------
-- All_Overloads --
-------------------
procedure All_Overloads is
begin
for J in All_Interp.First .. All_Interp.Last loop
if Present (All_Interp.Table (J).Nam) then
Write_Entity_Info (All_Interp.Table (J). Nam, " ");
else
Write_Str ("No Interp");
Write_Eol;
end if;
Write_Str ("=================");
Write_Eol;
end loop;
end All_Overloads;
--------------------------------------
-- Binary_Op_Interp_Has_Abstract_Op --
--------------------------------------
function Binary_Op_Interp_Has_Abstract_Op
(N : Node_Id;
E : Entity_Id) return Entity_Id
is
Abstr_Op : Entity_Id;
E_Left : constant Node_Id := First_Formal (E);
E_Right : constant Node_Id := Next_Formal (E_Left);
begin
Abstr_Op := Has_Abstract_Op (Left_Opnd (N), Etype (E_Left));
if Present (Abstr_Op) then
return Abstr_Op;
end if;
return Has_Abstract_Op (Right_Opnd (N), Etype (E_Right));
end Binary_Op_Interp_Has_Abstract_Op;
---------------------
-- Collect_Interps --
---------------------
procedure Collect_Interps (N : Node_Id) is
Ent : constant Entity_Id := Entity (N);
H : Entity_Id;
First_Interp : Interp_Index;
function Within_Instance (E : Entity_Id) return Boolean;
-- Within an instance there can be spurious ambiguities between a local
-- entity and one declared outside of the instance. This can only happen
-- for subprograms, because otherwise the local entity hides the outer
-- one. For an overloadable entity, this predicate determines whether it
-- is a candidate within the instance, or must be ignored.
---------------------
-- Within_Instance --
---------------------
function Within_Instance (E : Entity_Id) return Boolean is
Inst : Entity_Id;
Scop : Entity_Id;
begin
if not In_Instance then
return False;
end if;
Inst := Current_Scope;
while Present (Inst) and then not Is_Generic_Instance (Inst) loop
Inst := Scope (Inst);
end loop;
Scop := Scope (E);
while Present (Scop) and then Scop /= Standard_Standard loop
if Scop = Inst then
return True;
end if;
Scop := Scope (Scop);
end loop;
return False;
end Within_Instance;
-- Start of processing for Collect_Interps
begin
New_Interps (N);
-- Unconditionally add the entity that was initially matched
First_Interp := All_Interp.Last;
Add_One_Interp (N, Ent, Etype (N));
-- For expanded name, pick up all additional entities from the
-- same scope, since these are obviously also visible. Note that
-- these are not necessarily contiguous on the homonym chain.
if Nkind (N) = N_Expanded_Name then
H := Homonym (Ent);
while Present (H) loop
if Scope (H) = Scope (Entity (N)) then
Add_One_Interp (N, H, Etype (H));
end if;
H := Homonym (H);
end loop;
-- Case of direct name
else
-- First, search the homonym chain for directly visible entities
H := Current_Entity (Ent);
while Present (H) loop
exit when
not Is_Overloadable (H)
and then Is_Immediately_Visible (H);
if Is_Immediately_Visible (H) and then H /= Ent then
-- Only add interpretation if not hidden by an inner
-- immediately visible one.
for J in First_Interp .. All_Interp.Last - 1 loop
-- Current homograph is not hidden. Add to overloads
if not Is_Immediately_Visible (All_Interp.Table (J).Nam) then
exit;
-- Homograph is hidden, unless it is a predefined operator
elsif Type_Conformant (H, All_Interp.Table (J).Nam) then
-- A homograph in the same scope can occur within an
-- instantiation, the resulting ambiguity has to be
-- resolved later. The homographs may both be local
-- functions or actuals, or may be declared at different
-- levels within the instance. The renaming of an actual
-- within the instance must not be included.
if Within_Instance (H)
and then H /= Renamed_Entity (Ent)
and then not Is_Inherited_Operation (H)
then
All_Interp.Table (All_Interp.Last) :=
(H, Etype (H), Empty);
All_Interp.Append (No_Interp);
goto Next_Homograph;
elsif Scope (H) /= Standard_Standard then
goto Next_Homograph;
end if;
end if;
end loop;
-- On exit, we know that current homograph is not hidden
Add_One_Interp (N, H, Etype (H));
if Debug_Flag_E then
Write_Str ("Add overloaded interpretation ");
Write_Int (Int (H));
Write_Eol;
end if;
end if;
<<Next_Homograph>>
H := Homonym (H);
end loop;
-- Scan list of homographs for use-visible entities only
H := Current_Entity (Ent);
while Present (H) loop
if Is_Potentially_Use_Visible (H)
and then H /= Ent
and then Is_Overloadable (H)
then
for J in First_Interp .. All_Interp.Last - 1 loop
if not Is_Immediately_Visible (All_Interp.Table (J).Nam) then
exit;
elsif Type_Conformant (H, All_Interp.Table (J).Nam) then
goto Next_Use_Homograph;
end if;
end loop;
Add_One_Interp (N, H, Etype (H));
end if;
<<Next_Use_Homograph>>
H := Homonym (H);
end loop;
end if;
if All_Interp.Last = First_Interp + 1 then
-- The final interpretation is in fact not overloaded. Note that the
-- unique legal interpretation may or may not be the original one,
-- so we need to update N's entity and etype now, because once N
-- is marked as not overloaded it is also expected to carry the
-- proper interpretation.
Set_Is_Overloaded (N, False);
Set_Entity (N, All_Interp.Table (First_Interp).Nam);
Set_Etype (N, All_Interp.Table (First_Interp).Typ);
end if;
end Collect_Interps;
------------
-- Covers --
------------
function Covers (T1, T2 : Entity_Id) return Boolean is
BT1 : Entity_Id;
BT2 : Entity_Id;
function Full_View_Covers (Typ1, Typ2 : Entity_Id) return Boolean;
-- In an instance the proper view may not always be correct for
-- private types, but private and full view are compatible. This
-- removes spurious errors from nested instantiations that involve,
-- among other things, types derived from private types.
function Real_Actual (T : Entity_Id) return Entity_Id;
-- If an actual in an inner instance is the formal of an enclosing
-- generic, the actual in the enclosing instance is the one that can
-- create an accidental ambiguity, and the check on compatibily of
-- generic actual types must use this enclosing actual.
----------------------
-- Full_View_Covers --
----------------------
function Full_View_Covers (Typ1, Typ2 : Entity_Id) return Boolean is
begin
if Present (Full_View (Typ1))
and then Covers (Full_View (Typ1), Typ2)
then
return True;
elsif Present (Underlying_Full_View (Typ1))
and then Covers (Underlying_Full_View (Typ1), Typ2)
then
return True;
else
return False;
end if;
end Full_View_Covers;
-----------------
-- Real_Actual --
-----------------
function Real_Actual (T : Entity_Id) return Entity_Id is
Par : constant Node_Id := Parent (T);
RA : Entity_Id;
begin
-- Retrieve parent subtype from subtype declaration for actual
if Nkind (Par) = N_Subtype_Declaration
and then not Comes_From_Source (Par)
and then Is_Entity_Name (Subtype_Indication (Par))
then
RA := Entity (Subtype_Indication (Par));
if Is_Generic_Actual_Type (RA) then
return RA;
end if;
end if;
-- Otherwise actual is not the actual of an enclosing instance
return T;
end Real_Actual;
-- Start of processing for Covers
begin
-- If either operand is missing, then this is an error, but ignore it
-- and pretend we have a cover if errors already detected since this may
-- simply mean we have malformed trees or a semantic error upstream.
if No (T1) or else No (T2) then
if Total_Errors_Detected /= 0 then
return True;
else
raise Program_Error;
end if;
end if;
-- Trivial case: same types are always compatible
if T1 = T2 then
return True;
end if;
-- First check for Standard_Void_Type, which is special. Subsequent
-- processing in this routine assumes T1 and T2 are bona fide types;
-- Standard_Void_Type is a special entity that has some, but not all,
-- properties of types.
if T1 = Standard_Void_Type or else T2 = Standard_Void_Type then
return False;
end if;
BT1 := Base_Type (T1);
BT2 := Base_Type (T2);
-- Handle underlying view of records with unknown discriminants
-- using the original entity that motivated the construction of
-- this underlying record view (see Build_Derived_Private_Type).
if Is_Underlying_Record_View (BT1) then
BT1 := Underlying_Record_View (BT1);
end if;
if Is_Underlying_Record_View (BT2) then
BT2 := Underlying_Record_View (BT2);
end if;
-- Simplest case: types that have the same base type and are not generic
-- actuals are compatible. Generic actuals belong to their class but are
-- not compatible with other types of their class, and in particular
-- with other generic actuals. They are however compatible with their
-- own subtypes, and itypes with the same base are compatible as well.
-- Similarly, constrained subtypes obtained from expressions of an
-- unconstrained nominal type are compatible with the base type (may
-- lead to spurious ambiguities in obscure cases ???)
-- Generic actuals require special treatment to avoid spurious ambi-
-- guities in an instance, when two formal types are instantiated with
-- the same actual, so that different subprograms end up with the same
-- signature in the instance. If a generic actual is the actual of an
-- enclosing instance, it is that actual that we must compare: generic
-- actuals are only incompatible if they appear in the same instance.
if BT1 = BT2
or else BT1 = T2
or else BT2 = T1
then
if not Is_Generic_Actual_Type (T1)
or else
not Is_Generic_Actual_Type (T2)
then
return True;
-- Both T1 and T2 are generic actual types
else
declare
RT1 : constant Entity_Id := Real_Actual (T1);
RT2 : constant Entity_Id := Real_Actual (T2);
begin
return RT1 = RT2
or else Is_Itype (T1)
or else Is_Itype (T2)
or else Is_Constr_Subt_For_U_Nominal (T1)
or else Is_Constr_Subt_For_U_Nominal (T2)
or else Scope (RT1) /= Scope (RT2);
end;
end if;
-- Literals are compatible with types in a given "class"
elsif (T2 = Universal_Integer and then Is_Integer_Type (T1))
or else (T2 = Universal_Real and then Is_Real_Type (T1))
or else (T2 = Universal_Fixed and then Is_Fixed_Point_Type (T1))
or else (T2 = Any_Fixed and then Is_Fixed_Point_Type (T1))
or else (T2 = Any_Character and then Is_Character_Type (T1))
or else (T2 = Any_String and then Is_String_Type (T1))
or else (T2 = Any_Access and then Is_Access_Type (T1))
then
return True;
-- The context may be class wide, and a class-wide type is compatible
-- with any member of the class.
elsif Is_Class_Wide_Type (T1)
and then Is_Ancestor (Root_Type (T1), T2)
then
return True;
elsif Is_Class_Wide_Type (T1)
and then Is_Class_Wide_Type (T2)
and then Base_Type (Etype (T1)) = Base_Type (Etype (T2))
then
return True;
-- Ada 2005 (AI-345): A class-wide abstract interface type covers a
-- task_type or protected_type that implements the interface.
elsif Ada_Version >= Ada_2005
and then Is_Concurrent_Type (T2)
and then Is_Class_Wide_Type (T1)
and then Is_Interface (Etype (T1))
and then Interface_Present_In_Ancestor
(Typ => BT2, Iface => Etype (T1))
then
return True;
-- Ada 2005 (AI-251): A class-wide abstract interface type T1 covers an
-- object T2 implementing T1.
elsif Ada_Version >= Ada_2005
and then Is_Tagged_Type (T2)
and then Is_Class_Wide_Type (T1)
and then Is_Interface (Etype (T1))
then
if Interface_Present_In_Ancestor (Typ => T2,
Iface => Etype (T1))
then
return True;
end if;
declare
E : Entity_Id;
Elmt : Elmt_Id;
begin
if Is_Concurrent_Type (BT2) then
E := Corresponding_Record_Type (BT2);
else
E := BT2;
end if;
-- Ada 2005 (AI-251): A class-wide abstract interface type T1
-- covers an object T2 that implements a direct derivation of T1.
-- Note: test for presence of E is defense against previous error.
if No (E) then
Check_Error_Detected;
-- Here we have a corresponding record type
elsif Present (Interfaces (E)) then
Elmt := First_Elmt (Interfaces (E));
while Present (Elmt) loop
if Is_Ancestor (Etype (T1), Node (Elmt)) then
return True;
else
Next_Elmt (Elmt);
end if;
end loop;
end if;
-- We should also check the case in which T1 is an ancestor of
-- some implemented interface???
return False;
end;
-- In a dispatching call, the formal is of some specific type, and the
-- actual is of the corresponding class-wide type, including a subtype
-- of the class-wide type.
elsif Is_Class_Wide_Type (T2)
and then
(Class_Wide_Type (T1) = Class_Wide_Type (T2)
or else Base_Type (Root_Type (T2)) = BT1)
then
return True;
-- Some contexts require a class of types rather than a specific type.
-- For example, conditions require any boolean type, fixed point
-- attributes require some real type, etc. The built-in types Any_XXX
-- represent these classes.
elsif (T1 = Any_Integer and then Is_Integer_Type (T2))
or else (T1 = Any_Boolean and then Is_Boolean_Type (T2))
or else (T1 = Any_Real and then Is_Real_Type (T2))
or else (T1 = Any_Fixed and then Is_Fixed_Point_Type (T2))
or else (T1 = Any_Discrete and then Is_Discrete_Type (T2))
then
return True;
-- An aggregate is compatible with an array or record type
elsif T2 = Any_Composite and then Is_Aggregate_Type (T1) then
return True;
-- In Ada_2022, an aggregate is compatible with the type that
-- as the corresponding aspect.
elsif Ada_Version >= Ada_2022
and then T2 = Any_Composite
and then Present (Find_Aspect (T1, Aspect_Aggregate))
then
return True;
-- If the expected type is an anonymous access, the designated type must
-- cover that of the expression. Use the base type for this check: even
-- though access subtypes are rare in sources, they are generated for
-- actuals in instantiations.
elsif Ekind (BT1) = E_Anonymous_Access_Type
and then Is_Access_Type (T2)
and then Covers (Designated_Type (T1), Designated_Type (T2))
then
return True;
-- Ada 2012 (AI05-0149): Allow an anonymous access type in the context
-- of a named general access type. An implicit conversion will be
-- applied. For the resolution, the designated types must match if
-- untagged; further, if the designated type is tagged, the designated
-- type of the anonymous access type shall be covered by the designated
-- type of the named access type.
elsif Ada_Version >= Ada_2012
and then Ekind (BT1) = E_General_Access_Type
and then Ekind (BT2) = E_Anonymous_Access_Type
and then Covers (Designated_Type (T1), Designated_Type (T2))
and then (Is_Class_Wide_Type (Designated_Type (T1)) >=
Is_Class_Wide_Type (Designated_Type (T2)))
then
return True;
-- An Access_To_Subprogram is compatible with itself, or with an
-- anonymous type created for an attribute reference Access.
elsif Ekind (BT1) in E_Access_Subprogram_Type
| E_Access_Protected_Subprogram_Type
and then Is_Access_Type (T2)
and then (not Comes_From_Source (T1)
or else not Comes_From_Source (T2))
and then (Is_Overloadable (Designated_Type (T2))
or else Ekind (Designated_Type (T2)) = E_Subprogram_Type)
and then Type_Conformant (Designated_Type (T1), Designated_Type (T2))
and then Mode_Conformant (Designated_Type (T1), Designated_Type (T2))
then
return True;
-- Ada 2005 (AI-254): An Anonymous_Access_To_Subprogram is compatible
-- with itself, or with an anonymous type created for an attribute
-- reference Access.
elsif Ekind (BT1) in E_Anonymous_Access_Subprogram_Type
| E_Anonymous_Access_Protected_Subprogram_Type
and then Is_Access_Type (T2)
and then (not Comes_From_Source (T1)
or else not Comes_From_Source (T2))
and then (Is_Overloadable (Designated_Type (T2))
or else Ekind (Designated_Type (T2)) = E_Subprogram_Type)
and then Type_Conformant (Designated_Type (T1), Designated_Type (T2))
and then Mode_Conformant (Designated_Type (T1), Designated_Type (T2))
then
return True;
-- The context can be a remote access type, and the expression the
-- corresponding source type declared in a categorized package, or
-- vice versa.
elsif Is_Record_Type (T1)
and then (Is_Remote_Call_Interface (T1) or else Is_Remote_Types (T1))
and then Present (Corresponding_Remote_Type (T1))
then
return Covers (Corresponding_Remote_Type (T1), T2);
-- and conversely.
elsif Is_Record_Type (T2)
and then (Is_Remote_Call_Interface (T2) or else Is_Remote_Types (T2))
and then Present (Corresponding_Remote_Type (T2))
then
return Covers (Corresponding_Remote_Type (T2), T1);
-- Synchronized types are represented at run time by their corresponding
-- record type. During expansion one is replaced with the other, but
-- they are compatible views of the same type.
elsif Is_Record_Type (T1)
and then Is_Concurrent_Type (T2)
and then Present (Corresponding_Record_Type (T2))
then
return Covers (T1, Corresponding_Record_Type (T2));
elsif Is_Concurrent_Type (T1)
and then Present (Corresponding_Record_Type (T1))
and then Is_Record_Type (T2)
then
return Covers (Corresponding_Record_Type (T1), T2);
-- During analysis, an attribute reference 'Access has a special type
-- kind: Access_Attribute_Type, to be replaced eventually with the type
-- imposed by context.
elsif Ekind (T2) = E_Access_Attribute_Type
and then Ekind (BT1) in E_General_Access_Type | E_Access_Type
and then Covers (Designated_Type (T1), Designated_Type (T2))
then
-- If the target type is a RACW type while the source is an access
-- attribute type, we are building a RACW that may be exported.
if Is_Remote_Access_To_Class_Wide_Type (BT1) then
Set_Has_RACW (Current_Sem_Unit);
end if;
return True;
-- Ditto for allocators, which eventually resolve to the context type
elsif Ekind (T2) = E_Allocator_Type and then Is_Access_Type (T1) then
return Covers (Designated_Type (T1), Designated_Type (T2))
or else
(From_Limited_With (Designated_Type (T1))
and then Covers (Designated_Type (T2), Designated_Type (T1)));
-- A boolean operation on integer literals is compatible with modular
-- context.
elsif T2 = Any_Modular and then Is_Modular_Integer_Type (T1) then
return True;
-- The actual type may be the result of a previous error
elsif BT2 = Any_Type then
return True;
-- A Raise_Expressions is legal in any expression context
elsif BT2 = Raise_Type then
return True;
-- A packed array type covers its corresponding non-packed type. This is
-- not legitimate Ada, but allows the omission of a number of otherwise
-- useless unchecked conversions, and since this can only arise in
-- (known correct) expanded code, no harm is done.
elsif Is_Packed_Array (T2)
and then T1 = Packed_Array_Impl_Type (T2)
then
return True;
-- Similarly an array type covers its corresponding packed array type
elsif Is_Packed_Array (T1)
and then T2 = Packed_Array_Impl_Type (T1)
then
return True;
-- In instances, or with types exported from instantiations, check
-- whether a partial and a full view match. Verify that types are
-- legal, to prevent cascaded errors.
elsif Is_Private_Type (T1)
and then (In_Instance
or else (Is_Type (T2) and then Is_Generic_Actual_Type (T2)))
and then Full_View_Covers (T1, T2)
then
return True;
elsif Is_Private_Type (T2)
and then (In_Instance
or else (Is_Type (T1) and then Is_Generic_Actual_Type (T1)))
and then Full_View_Covers (T2, T1)
then
return True;
-- In the expansion of inlined bodies, types are compatible if they
-- are structurally equivalent.
elsif In_Inlined_Body
and then (Underlying_Type (T1) = Underlying_Type (T2)
or else
(Is_Access_Type (T1)
and then Is_Access_Type (T2)
and then Designated_Type (T1) = Designated_Type (T2))
or else
(T1 = Any_Access
and then Is_Access_Type (Underlying_Type (T2)))
or else
(T2 = Any_Composite
and then Is_Composite_Type (Underlying_Type (T1))))
then
return True;
-- Ada 2005 (AI-50217): Additional branches to make the shadow entity
-- obtained through a limited_with compatible with its real entity.
elsif From_Limited_With (T1) then
-- If the expected type is the nonlimited view of a type, the
-- expression may have the limited view. If that one in turn is
-- incomplete, get full view if available.
return Has_Non_Limited_View (T1)
and then Covers (Get_Full_View (Non_Limited_View (T1)), T2);
elsif From_Limited_With (T2) then
-- If units in the context have Limited_With clauses on each other,
-- either type might have a limited view. Checks performed elsewhere
-- verify that the context type is the nonlimited view.
return Has_Non_Limited_View (T2)
and then Covers (T1, Get_Full_View (Non_Limited_View (T2)));
-- Ada 2005 (AI-412): Coverage for regular incomplete subtypes
elsif Ekind (T1) = E_Incomplete_Subtype then
return Covers (Full_View (Etype (T1)), T2);
elsif Ekind (T2) = E_Incomplete_Subtype then
return Covers (T1, Full_View (Etype (T2)));
-- Ada 2005 (AI-423): Coverage of formal anonymous access types
-- and actual anonymous access types in the context of generic
-- instantiations. We have the following situation:
-- generic
-- type Formal is private;
-- Formal_Obj : access Formal; -- T1
-- package G is ...
-- package P is
-- type Actual is ...
-- Actual_Obj : access Actual; -- T2
-- package Instance is new G (Formal => Actual,
-- Formal_Obj => Actual_Obj);
elsif Ada_Version >= Ada_2005
and then Is_Anonymous_Access_Type (T1)
and then Is_Anonymous_Access_Type (T2)
and then Is_Generic_Type (Directly_Designated_Type (T1))
and then Get_Instance_Of (Directly_Designated_Type (T1)) =
Directly_Designated_Type (T2)
then
return True;
-- Otherwise, types are not compatible
else
return False;
end if;
end Covers;
------------------
-- Disambiguate --
------------------
function Disambiguate
(N : Node_Id;
I1, I2 : Interp_Index;
Typ : Entity_Id) return Interp
is
I : Interp_Index;
It : Interp;
It1, It2 : Interp;
Nam1, Nam2 : Entity_Id;
Predef_Subp : Entity_Id;
User_Subp : Entity_Id;
function Inherited_From_Actual (S : Entity_Id) return Boolean;
-- Determine whether one of the candidates is an operation inherited by
-- a type that is derived from an actual in an instantiation.
function In_Same_Declaration_List
(Typ : Entity_Id;
Op_Decl : Entity_Id) return Boolean;
-- AI05-0020: a spurious ambiguity may arise when equality on anonymous
-- access types is declared on the partial view of a designated type, so
-- that the type declaration and equality are not in the same list of
-- declarations. This AI gives a preference rule for the user-defined
-- operation. Same rule applies for arithmetic operations on private
-- types completed with fixed-point types: the predefined operation is
-- hidden; this is already handled properly in GNAT.
function Is_Actual_Subprogram (S : Entity_Id) return Boolean;
-- Determine whether a subprogram is an actual in an enclosing instance.
-- An overloading between such a subprogram and one declared outside the
-- instance is resolved in favor of the first, because it resolved in
-- the generic. Within the instance the actual is represented by a
-- constructed subprogram renaming.
function Matches (Op : Node_Id; Func_Id : Entity_Id) return Boolean;
-- Determine whether function Func_Id is an exact match for binary or
-- unary operator Op.
function Operand_Type return Entity_Id;
-- Determine type of operand for an equality operation, to apply Ada
-- 2005 rules to equality on anonymous access types.
function Standard_Operator return Boolean;
-- Check whether subprogram is predefined operator declared in Standard.
-- It may given by an operator name, or by an expanded name whose prefix
-- is Standard.
function Remove_Conversions return Interp;
-- Last chance for pathological cases involving comparisons on literals,
-- and user overloadings of the same operator. Such pathologies have
-- been removed from the ACVC, but still appear in two DEC tests, with
-- the following notable quote from Ben Brosgol:
--
-- [Note: I disclaim all credit/responsibility/blame for coming up with
-- this example; Robert Dewar brought it to our attention, since it is
-- apparently found in the ACVC 1.5. I did not attempt to find the
-- reason in the Reference Manual that makes the example legal, since I
-- was too nauseated by it to want to pursue it further.]
--
-- Accordingly, this is not a fully recursive solution, but it handles
-- DEC tests c460vsa, c460vsb. It also handles ai00136a, which pushes
-- pathology in the other direction with calls whose multiple overloaded
-- actuals make them truly unresolvable.
-- The new rules concerning abstract operations create additional need
-- for special handling of expressions with universal operands, see
-- comments to Has_Abstract_Interpretation below.
function Is_User_Defined_Anonymous_Access_Equality
(User_Subp, Predef_Subp : Entity_Id) return Boolean;
-- Check for Ada 2005, AI-020: If the context involves an anonymous
-- access operand, recognize a user-defined equality (User_Subp) with
-- the proper signature, declared in the same declarative list as the
-- type and not hiding a predefined equality Predef_Subp.
---------------------------
-- Inherited_From_Actual --
---------------------------
function Inherited_From_Actual (S : Entity_Id) return Boolean is
Par : constant Node_Id := Parent (S);
begin
if Nkind (Par) /= N_Full_Type_Declaration
or else Nkind (Type_Definition (Par)) /= N_Derived_Type_Definition
then
return False;
else
return Is_Entity_Name (Subtype_Indication (Type_Definition (Par)))
and then
Is_Generic_Actual_Type (
Entity (Subtype_Indication (Type_Definition (Par))));
end if;
end Inherited_From_Actual;
------------------------------
-- In_Same_Declaration_List --
------------------------------
function In_Same_Declaration_List
(Typ : Entity_Id;
Op_Decl : Entity_Id) return Boolean
is
Scop : constant Entity_Id := Scope (Typ);
begin
return In_Same_List (Parent (Typ), Op_Decl)
or else
(Is_Package_Or_Generic_Package (Scop)
and then List_Containing (Op_Decl) =
Visible_Declarations (Parent (Scop))
and then List_Containing (Parent (Typ)) =
Private_Declarations (Parent (Scop)));
end In_Same_Declaration_List;
--------------------------
-- Is_Actual_Subprogram --
--------------------------
function Is_Actual_Subprogram (S : Entity_Id) return Boolean is
begin
return In_Open_Scopes (Scope (S))
and then Nkind (Unit_Declaration_Node (S)) =
N_Subprogram_Renaming_Declaration
-- Why the Comes_From_Source test here???
and then not Comes_From_Source (Unit_Declaration_Node (S))
and then
(Is_Generic_Instance (Scope (S))
or else Is_Wrapper_Package (Scope (S)));
end Is_Actual_Subprogram;
-------------
-- Matches --
-------------
function Matches (Op : Node_Id; Func_Id : Entity_Id) return Boolean is
function Matching_Types
(Opnd_Typ : Entity_Id;
Formal_Typ : Entity_Id) return Boolean;
-- Determine whether operand type Opnd_Typ and formal parameter type
-- Formal_Typ are either the same or compatible.
--------------------
-- Matching_Types --
--------------------
function Matching_Types
(Opnd_Typ : Entity_Id;
Formal_Typ : Entity_Id) return Boolean
is
begin
-- A direct match
if Opnd_Typ = Formal_Typ then
return True;
-- Any integer type matches universal integer
elsif Opnd_Typ = Universal_Integer
and then Is_Integer_Type (Formal_Typ)
then
return True;
-- Any floating point type matches universal real
elsif Opnd_Typ = Universal_Real
and then Is_Floating_Point_Type (Formal_Typ)
then
return True;
-- The type of the formal parameter maps a generic actual type to
-- a generic formal type. If the operand type is the type being
-- mapped in an instance, then this is a match.
elsif Is_Generic_Actual_Type (Formal_Typ)
and then Etype (Formal_Typ) = Opnd_Typ
then
return True;
-- ??? There are possibly other cases to consider
else
return False;
end if;
end Matching_Types;
-- Local variables
F1 : constant Entity_Id := First_Formal (Func_Id);
F1_Typ : constant Entity_Id := Etype (F1);
F2 : constant Entity_Id := Next_Formal (F1);
F2_Typ : constant Entity_Id := Etype (F2);
Lop_Typ : constant Entity_Id := Etype (Left_Opnd (Op));
Rop_Typ : constant Entity_Id := Etype (Right_Opnd (Op));
-- Start of processing for Matches
begin
if Lop_Typ = F1_Typ then
return Matching_Types (Rop_Typ, F2_Typ);
elsif Rop_Typ = F2_Typ then
return Matching_Types (Lop_Typ, F1_Typ);
-- Otherwise this is not a good match because each operand-formal
-- pair is compatible only on base-type basis, which is not specific
-- enough.
else
return False;
end if;
end Matches;
------------------
-- Operand_Type --
------------------
function Operand_Type return Entity_Id is
Opnd : Node_Id;
begin
if Nkind (N) = N_Function_Call then
Opnd := First_Actual (N);
else
Opnd := Left_Opnd (N);
end if;
return Etype (Opnd);
end Operand_Type;
------------------------
-- Remove_Conversions --
------------------------
function Remove_Conversions return Interp is
I : Interp_Index;
It : Interp;
It1 : Interp;
F1 : Entity_Id;
Act1 : Node_Id;
Act2 : Node_Id;
function Has_Abstract_Interpretation (N : Node_Id) return Boolean;
-- If an operation has universal operands the universal operation
-- is present among its interpretations. If there is an abstract
-- interpretation for the operator, with a numeric result, this
-- interpretation was already removed in sem_ch4, but the universal
-- one is still visible. We must rescan the list of operators and
-- remove the universal interpretation to resolve the ambiguity.
---------------------------------
-- Has_Abstract_Interpretation --
---------------------------------
function Has_Abstract_Interpretation (N : Node_Id) return Boolean is
E : Entity_Id;
begin
if Nkind (N) not in N_Op
or else Ada_Version < Ada_2005
or else not Is_Overloaded (N)
or else No (Universal_Interpretation (N))
then
return False;
else
E := Get_Name_Entity_Id (Chars (N));
while Present (E) loop
if Is_Overloadable (E)
and then Is_Abstract_Subprogram (E)
and then Is_Numeric_Type (Etype (E))
then
return True;
else
E := Homonym (E);
end if;
end loop;
-- Finally, if an operand of the binary operator is itself
-- an operator, recurse to see whether its own abstract
-- interpretation is responsible for the spurious ambiguity.
if Nkind (N) in N_Binary_Op then
return Has_Abstract_Interpretation (Left_Opnd (N))
or else Has_Abstract_Interpretation (Right_Opnd (N));
elsif Nkind (N) in N_Unary_Op then
return Has_Abstract_Interpretation (Right_Opnd (N));
else
return False;
end if;
end if;
end Has_Abstract_Interpretation;
-- Start of processing for Remove_Conversions
begin
It1 := No_Interp;
Get_First_Interp (N, I, It);
while Present (It.Typ) loop
if not Is_Overloadable (It.Nam) then
return No_Interp;
end if;
F1 := First_Formal (It.Nam);
if No (F1) then
return It1;
else
if Nkind (N) in N_Subprogram_Call then
Act1 := First_Actual (N);
if Present (Act1) then
Act2 := Next_Actual (Act1);
else
Act2 := Empty;
end if;
elsif Nkind (N) in N_Unary_Op then
Act1 := Right_Opnd (N);
Act2 := Empty;
elsif Nkind (N) in N_Binary_Op then
Act1 := Left_Opnd (N);
Act2 := Right_Opnd (N);
-- Use the type of the second formal, so as to include
-- exponentiation, where the exponent may be ambiguous and
-- the result non-universal.
Next_Formal (F1);
else
return It1;
end if;
if Nkind (Act1) in N_Op
and then Is_Overloaded (Act1)
and then
(Nkind (Act1) in N_Unary_Op
or else Nkind (Left_Opnd (Act1)) in
N_Integer_Literal | N_Real_Literal)
and then Nkind (Right_Opnd (Act1)) in
N_Integer_Literal | N_Real_Literal
and then Has_Compatible_Type (Act1, Standard_Boolean)
and then Etype (F1) = Standard_Boolean
then
-- If the two candidates are the original ones, the
-- ambiguity is real. Otherwise keep the original, further
-- calls to Disambiguate will take care of others in the
-- list of candidates.
if It1 /= No_Interp then
if It = Disambiguate.It1
or else It = Disambiguate.It2
then
if It1 = Disambiguate.It1
or else It1 = Disambiguate.It2
then
return No_Interp;
else
It1 := It;
end if;
end if;
elsif Present (Act2)
and then Nkind (Act2) in N_Op
and then Is_Overloaded (Act2)
and then Nkind (Right_Opnd (Act2)) in
N_Integer_Literal | N_Real_Literal
and then Has_Compatible_Type (Act2, Standard_Boolean)
then
-- The preference rule on the first actual is not
-- sufficient to disambiguate.
goto Next_Interp;
else
It1 := It;
end if;
elsif Is_Numeric_Type (Etype (F1))
and then Has_Abstract_Interpretation (Act1)
then
-- Current interpretation is not the right one because it
-- expects a numeric operand. Examine all the other ones.
declare
I : Interp_Index;
It : Interp;
begin
Get_First_Interp (N, I, It);
while Present (It.Typ) loop
if
not Is_Numeric_Type (Etype (First_Formal (It.Nam)))
then
if No (Act2)
or else not Has_Abstract_Interpretation (Act2)
or else not
Is_Numeric_Type
(Etype (Next_Formal (First_Formal (It.Nam))))
then
return It;
end if;
end if;
Get_Next_Interp (I, It);
end loop;
return No_Interp;
end;
end if;
end if;
<<Next_Interp>>
Get_Next_Interp (I, It);
end loop;
-- After some error, a formal may have Any_Type and yield a spurious
-- match. To avoid cascaded errors if possible, check for such a
-- formal in either candidate.
if Serious_Errors_Detected > 0 then
declare
Formal : Entity_Id;
begin
Formal := First_Formal (Nam1);
while Present (Formal) loop
if Etype (Formal) = Any_Type then
return Disambiguate.It2;
end if;
Next_Formal (Formal);
end loop;
Formal := First_Formal (Nam2);
while Present (Formal) loop
if Etype (Formal) = Any_Type then
return Disambiguate.It1;
end if;
Next_Formal (Formal);
end loop;
end;
end if;
return It1;
end Remove_Conversions;
-----------------------
-- Standard_Operator --
-----------------------
function Standard_Operator return Boolean is
Nam : Node_Id;
begin
if Nkind (N) in N_Op then
return True;
elsif Nkind (N) = N_Function_Call then
Nam := Name (N);
if Nkind (Nam) /= N_Expanded_Name then
return True;
else
return Entity (Prefix (Nam)) = Standard_Standard;
end if;
else
return False;
end if;
end Standard_Operator;
-----------------------------------------------
-- Is_User_Defined_Anonymous_Access_Equality --
-----------------------------------------------
function Is_User_Defined_Anonymous_Access_Equality
(User_Subp, Predef_Subp : Entity_Id) return Boolean is
begin
return Present (User_Subp)
-- Check for Ada 2005 and use of anonymous access
and then Ada_Version >= Ada_2005
and then Etype (User_Subp) = Standard_Boolean
and then Is_Anonymous_Access_Type (Operand_Type)
-- This check is only relevant if User_Subp is visible and not in
-- an instance
and then (In_Open_Scopes (Scope (User_Subp))
or else Is_Potentially_Use_Visible (User_Subp))
and then not In_Instance
and then not Hides_Op (User_Subp, Predef_Subp)
-- Is User_Subp declared in the same declarative list as the type?
and then
In_Same_Declaration_List
(Designated_Type (Operand_Type),
Unit_Declaration_Node (User_Subp));
end Is_User_Defined_Anonymous_Access_Equality;
-- Start of processing for Disambiguate
begin
-- Recover the two legal interpretations
Get_First_Interp (N, I, It);
while I /= I1 loop
Get_Next_Interp (I, It);
end loop;
It1 := It;
Nam1 := It.Nam;
while I /= I2 loop
Get_Next_Interp (I, It);
end loop;
It2 := It;
Nam2 := It.Nam;
-- Check whether one of the entities is an Ada 2005/2012/2022 and we
-- are operating in an earlier mode, in which case we discard the Ada
-- 2005/2012/2022 entity, so that we get proper Ada 95 overload
-- resolution.
if Ada_Version < Ada_2005 then
if Is_Ada_2005_Only (Nam1)
or else Is_Ada_2012_Only (Nam1)
or else Is_Ada_2022_Only (Nam1)
then
return It2;
elsif Is_Ada_2005_Only (Nam2)
or else Is_Ada_2012_Only (Nam2)
or else Is_Ada_2022_Only (Nam2)
then
return It1;
end if;
-- Check whether one of the entities is an Ada 2012/2022 entity and we
-- are operating in Ada 2005 mode, in which case we discard the Ada 2012
-- Ada 2022 entity, so that we get proper Ada 2005 overload resolution.
elsif Ada_Version = Ada_2005 then
if Is_Ada_2012_Only (Nam1) or else Is_Ada_2022_Only (Nam1) then
return It2;
elsif Is_Ada_2012_Only (Nam2) or else Is_Ada_2022_Only (Nam2) then
return It1;
end if;
-- Ditto for Ada 2012 vs Ada 2022.
elsif Ada_Version = Ada_2012 then
if Is_Ada_2022_Only (Nam1) then
return It2;
elsif Is_Ada_2022_Only (Nam2) then
return It1;
end if;
end if;
-- If the context is universal, the predefined operator is preferred.
-- This includes bounds in numeric type declarations, and expressions
-- in type conversions. If no interpretation yields a universal type,
-- then we must check whether the user-defined entity hides the prede-
-- fined one.
if Chars (Nam1) in Any_Operator_Name and then Standard_Operator then
if Typ = Universal_Integer
or else Typ = Universal_Real
or else Typ = Any_Integer
or else Typ = Any_Discrete
or else Typ = Any_Real
or else Typ = Any_Type
then
-- Find an interpretation that yields the universal type, or else
-- a predefined operator that yields a predefined numeric type.
declare
Candidate : Interp := No_Interp;
begin
Get_First_Interp (N, I, It);
while Present (It.Typ) loop
if Is_Universal_Numeric_Type (It.Typ)
and then (Typ = Any_Type or else Covers (Typ, It.Typ))
then
return It;
elsif Is_Numeric_Type (It.Typ)
and then Scope (It.Typ) = Standard_Standard
and then Scope (It.Nam) = Standard_Standard
and then Covers (Typ, It.Typ)
then
Candidate := It;
end if;
Get_Next_Interp (I, It);
end loop;
if Candidate /= No_Interp then
return Candidate;
end if;
end;
elsif Chars (Nam1) /= Name_Op_Not
and then (Typ = Standard_Boolean or else Typ = Any_Boolean)
then
-- Equality or comparison operation. Choose predefined operator if
-- arguments are universal. The node may be an operator, name, or
-- a function call, so unpack arguments accordingly.
declare
Arg1, Arg2 : Node_Id;
begin
if Nkind (N) in N_Op then
Arg1 := Left_Opnd (N);
Arg2 := Right_Opnd (N);
elsif Is_Entity_Name (N) then
Arg1 := First_Entity (Entity (N));
Arg2 := Next_Entity (Arg1);
else
Arg1 := First_Actual (N);
Arg2 := Next_Actual (Arg1);
end if;
if Present (Arg2) then
if Ekind (Nam1) = E_Operator then
Predef_Subp := Nam1;
User_Subp := Nam2;
elsif Ekind (Nam2) = E_Operator then
Predef_Subp := Nam2;
User_Subp := Nam1;
else
Predef_Subp := Empty;
User_Subp := Empty;
end if;
-- Take into account universal interpretation as well as
-- universal_access equality, as long as AI05-0020 does not
-- trigger.
if (Present (Universal_Interpretation (Arg1))
and then Universal_Interpretation (Arg2) =
Universal_Interpretation (Arg1))
or else
(Nkind (N) in N_Op_Eq | N_Op_Ne
and then (Is_Anonymous_Access_Type (Etype (Arg1))
or else
Is_Anonymous_Access_Type (Etype (Arg2)))
and then not
Is_User_Defined_Anonymous_Access_Equality
(User_Subp, Predef_Subp))
then
Get_First_Interp (N, I, It);
while Scope (It.Nam) /= Standard_Standard loop
Get_Next_Interp (I, It);
end loop;
return It;
end if;
end if;
end;
end if;
end if;
-- If no universal interpretation, check whether user-defined operator
-- hides predefined one, as well as other special cases. If the node
-- is a range, then one or both bounds are ambiguous. Each will have
-- to be disambiguated w.r.t. the context type. The type of the range
-- itself is imposed by the context, so we can return either legal
-- interpretation.
if Ekind (Nam1) = E_Operator then
Predef_Subp := Nam1;
User_Subp := Nam2;
elsif Ekind (Nam2) = E_Operator then
Predef_Subp := Nam2;
User_Subp := Nam1;
elsif Nkind (N) = N_Range then
return It1;
-- Implement AI05-105: A renaming declaration with an access
-- definition must resolve to an anonymous access type. This
-- is a resolution rule and can be used to disambiguate.
elsif Nkind (Parent (N)) = N_Object_Renaming_Declaration
and then Present (Access_Definition (Parent (N)))
then
if Is_Anonymous_Access_Type (It1.Typ) then
if Ekind (It2.Typ) = Ekind (It1.Typ) then
-- True ambiguity
return No_Interp;
else
return It1;
end if;
elsif Is_Anonymous_Access_Type (It2.Typ) then
return It2;
-- No legal interpretation
else
return No_Interp;
end if;
-- Two access attribute types may have been created for an expression
-- with an implicit dereference, which is automatically overloaded.
-- If both access attribute types designate the same object type,
-- disambiguation if any will take place elsewhere, so keep any one of
-- the interpretations.
elsif Ekind (It1.Typ) = E_Access_Attribute_Type
and then Ekind (It2.Typ) = E_Access_Attribute_Type
and then Designated_Type (It1.Typ) = Designated_Type (It2.Typ)
then
return It1;
-- If two user defined-subprograms are visible, it is a true ambiguity,
-- unless one of them is an entry and the context is a conditional or
-- timed entry call, or unless we are within an instance and this is
-- results from two formals types with the same actual.
else
if Nkind (N) = N_Procedure_Call_Statement
and then Nkind (Parent (N)) = N_Entry_Call_Alternative
and then N = Entry_Call_Statement (Parent (N))
then
if Ekind (Nam2) = E_Entry then
return It2;
elsif Ekind (Nam1) = E_Entry then
return It1;
else
return No_Interp;
end if;
-- If the ambiguity occurs within an instance, it is due to several
-- formal types with the same actual. Look for an exact match between
-- the types of the formals of the overloadable entities, and the
-- actuals in the call, to recover the unambiguous match in the
-- original generic.
-- The ambiguity can also be due to an overloading between a formal
-- subprogram and a subprogram declared outside the generic. If the
-- node is overloaded, it did not resolve to the global entity in
-- the generic, and we choose the formal subprogram.
-- Finally, the ambiguity can be between an explicit subprogram and
-- one inherited (with different defaults) from an actual. In this
-- case the resolution was to the explicit declaration in the
-- generic, and remains so in the instance.
-- The same sort of disambiguation needed for calls is also required
-- for the name given in a subprogram renaming, and that case is
-- handled here as well. We test Comes_From_Source to exclude this
-- treatment for implicit renamings created for formal subprograms.
elsif In_Instance and then not In_Generic_Actual (N) then
if Nkind (N) in N_Subprogram_Call
or else
(Nkind (N) in N_Has_Entity
and then
Nkind (Parent (N)) = N_Subprogram_Renaming_Declaration
and then Comes_From_Source (Parent (N)))
then
declare
Actual : Node_Id;
Formal : Entity_Id;
Renam : Entity_Id := Empty;
Is_Act1 : constant Boolean := Is_Actual_Subprogram (Nam1);
Is_Act2 : constant Boolean := Is_Actual_Subprogram (Nam2);
begin
if Is_Act1 and then not Is_Act2 then
return It1;
elsif Is_Act2 and then not Is_Act1 then
return It2;
elsif Inherited_From_Actual (Nam1)
and then Comes_From_Source (Nam2)
then
return It2;
elsif Inherited_From_Actual (Nam2)
and then Comes_From_Source (Nam1)
then
return It1;
end if;
-- In the case of a renamed subprogram, pick up the entity
-- of the renaming declaration so we can traverse its
-- formal parameters.
if Nkind (N) in N_Has_Entity then
Renam := Defining_Unit_Name (Specification (Parent (N)));
end if;
if Present (Renam) then
Actual := First_Formal (Renam);
else
Actual := First_Actual (N);
end if;
Formal := First_Formal (Nam1);
while Present (Actual) loop
if Etype (Actual) /= Etype (Formal) then
return It2;
end if;
if Present (Renam) then
Next_Formal (Actual);
else
Next_Actual (Actual);
end if;
Next_Formal (Formal);
end loop;
return It1;
end;
elsif Nkind (N) in N_Binary_Op then
if Matches (N, Nam1) then
return It1;
else
return It2;
end if;
elsif Nkind (N) in N_Unary_Op then
if Etype (Right_Opnd (N)) = Etype (First_Formal (Nam1)) then
return It1;
else
return It2;
end if;
else
return Remove_Conversions;
end if;
else
return Remove_Conversions;
end if;
end if;
-- An implicit concatenation operator on a string type cannot be
-- disambiguated from the predefined concatenation. This can only
-- happen with concatenation of string literals.
if Chars (User_Subp) = Name_Op_Concat
and then Ekind (User_Subp) = E_Operator
and then Is_String_Type (Etype (First_Formal (User_Subp)))
then
return No_Interp;
-- If the user-defined operator is in an open scope, or in the scope
-- of the resulting type, or given by an expanded name that names its
-- scope, it hides the predefined operator for the type. Exponentiation
-- has to be special-cased because the implicit operator does not have
-- a symmetric signature, and may not be hidden by the explicit one.
elsif (Nkind (N) = N_Function_Call
and then Nkind (Name (N)) = N_Expanded_Name
and then (Chars (Predef_Subp) /= Name_Op_Expon
or else Hides_Op (User_Subp, Predef_Subp))
and then Scope (User_Subp) = Entity (Prefix (Name (N))))
or else Hides_Op (User_Subp, Predef_Subp)
then
if It1.Nam = User_Subp then
return It1;
else
return It2;
end if;
-- Otherwise, the predefined operator has precedence, or if the user-
-- defined operation is directly visible we have a true ambiguity.
-- If this is a fixed-point multiplication and division in Ada 83 mode,
-- exclude the universal_fixed operator, which often causes ambiguities
-- in legacy code.
-- Ditto in Ada 2012, where an ambiguity may arise for an operation
-- on a partial view that is completed with a fixed point type. See
-- AI05-0020 and AI05-0209. The ambiguity is resolved in favor of the
-- user-defined type and subprogram, so that a client of the package
-- has the same resolution as the body of the package.
else
if (In_Open_Scopes (Scope (User_Subp))
or else Is_Potentially_Use_Visible (User_Subp))
and then not In_Instance
then
if Is_Fixed_Point_Type (Typ)
and then Chars (Nam1) in Name_Op_Multiply | Name_Op_Divide
and then
(Ada_Version = Ada_83
or else (Ada_Version >= Ada_2012
and then In_Same_Declaration_List
(First_Subtype (Typ),
Unit_Declaration_Node (User_Subp))))
then
if It2.Nam = Predef_Subp then
return It1;
else
return It2;
end if;
-- Check for AI05-020
elsif Chars (Nam1) in Name_Op_Eq | Name_Op_Ne
and then Is_User_Defined_Anonymous_Access_Equality
(User_Subp, Predef_Subp)
then
if It2.Nam = Predef_Subp then
return It1;
else
return It2;
end if;
-- An immediately visible operator hides a use-visible user-
-- defined operation. This disambiguation cannot take place
-- earlier because the visibility of the predefined operator
-- can only be established when operand types are known.
elsif Ekind (User_Subp) = E_Function
and then Ekind (Predef_Subp) = E_Operator
and then Nkind (N) in N_Op
and then not Is_Overloaded (Right_Opnd (N))
and then
Is_Immediately_Visible (Base_Type (Etype (Right_Opnd (N))))
and then Is_Potentially_Use_Visible (User_Subp)
then
if It2.Nam = Predef_Subp then
return It1;
else
return It2;
end if;
else
return No_Interp;
end if;
elsif It1.Nam = Predef_Subp then
return It1;
else
return It2;
end if;
end if;
end Disambiguate;
-------------------------
-- Entity_Matches_Spec --
-------------------------
function Entity_Matches_Spec (Old_S, New_S : Entity_Id) return Boolean is
begin
-- Simple case: same entity kinds, type conformance is required. A
-- parameterless function can also rename a literal.
if Ekind (Old_S) = Ekind (New_S)
or else (Ekind (New_S) = E_Function
and then Ekind (Old_S) = E_Enumeration_Literal)
then
return Type_Conformant (New_S, Old_S);
elsif Ekind (New_S) = E_Function and then Ekind (Old_S) = E_Operator then
return Operator_Matches_Spec (Old_S, New_S);
elsif Ekind (New_S) = E_Procedure and then Is_Entry (Old_S) then
return Type_Conformant (New_S, Old_S);
else
return False;
end if;
end Entity_Matches_Spec;
----------------------
-- Find_Unique_Type --
----------------------
function Find_Unique_Type (L : Node_Id; R : Node_Id) return Entity_Id is
T : constant Entity_Id := Etype (L);
I : Interp_Index;
It : Interp;
TR : Entity_Id := Any_Type;
begin
if Is_Overloaded (R) then
Get_First_Interp (R, I, It);
while Present (It.Typ) loop
if Covers (T, It.Typ) or else Covers (It.Typ, T) then
-- If several interpretations are possible and L is universal,
-- apply preference rule.
if TR /= Any_Type then
if Is_Universal_Numeric_Type (T)
and then It.Typ = T
then
TR := It.Typ;
end if;
else
TR := It.Typ;
end if;
end if;
Get_Next_Interp (I, It);
end loop;
Set_Etype (R, TR);
-- In the non-overloaded case, the Etype of R is already set correctly
else
null;
end if;
-- If one of the operands is Universal_Fixed, the type of the other
-- operand provides the context.
if Etype (R) = Universal_Fixed then
return T;
elsif T = Universal_Fixed then
return Etype (R);
-- If one operand is a raise_expression, use type of other operand
elsif Nkind (L) = N_Raise_Expression then
return Etype (R);
else
return Specific_Type (T, Etype (R));
end if;
end Find_Unique_Type;
-------------------------------------
-- Function_Interp_Has_Abstract_Op --
-------------------------------------
function Function_Interp_Has_Abstract_Op
(N : Node_Id;
E : Entity_Id) return Entity_Id
is
Abstr_Op : Entity_Id;
Act : Node_Id;
Act_Parm : Node_Id;
Form_Parm : Node_Id;
begin
-- Why is check on E needed below ???
-- In any case this para needs comments ???
if Is_Overloaded (N) and then Is_Overloadable (E) then
Act_Parm := First_Actual (N);
Form_Parm := First_Formal (E);
while Present (Act_Parm) and then Present (Form_Parm) loop
Act := Act_Parm;
if Nkind (Act) = N_Parameter_Association then
Act := Explicit_Actual_Parameter (Act);
end if;
Abstr_Op := Has_Abstract_Op (Act, Etype (Form_Parm));
if Present (Abstr_Op) then
return Abstr_Op;
end if;
Next_Actual (Act_Parm);
Next_Formal (Form_Parm);
end loop;
end if;
return Empty;
end Function_Interp_Has_Abstract_Op;
----------------------
-- Get_First_Interp --
----------------------
procedure Get_First_Interp
(N : Node_Id;
I : out Interp_Index;
It : out Interp)
is
Int_Ind : Interp_Index;
O_N : Node_Id;
begin
-- If a selected component is overloaded because the selector has
-- multiple interpretations, the node is a call to a protected
-- operation or an indirect call. Retrieve the interpretation from
-- the selector name. The selected component may be overloaded as well
-- if the prefix is overloaded. That case is unchanged.
if Nkind (N) = N_Selected_Component
and then Is_Overloaded (Selector_Name (N))
then
O_N := Selector_Name (N);
else
O_N := N;
end if;
Int_Ind := Interp_Map.Get (O_N);
-- Procedure should never be called if the node has no interpretations
if Int_Ind < 0 then
raise Program_Error;
end if;
I := Int_Ind;
It := All_Interp.Table (Int_Ind);
end Get_First_Interp;
---------------------
-- Get_Next_Interp --
---------------------
procedure Get_Next_Interp (I : in out Interp_Index; It : out Interp) is
begin
I := I + 1;
It := All_Interp.Table (I);
end Get_Next_Interp;
-------------------------
-- Has_Compatible_Type --
-------------------------
function Has_Compatible_Type
(N : Node_Id;
Typ : Entity_Id) return Boolean
is
I : Interp_Index;
It : Interp;
begin
if N = Error then
return False;
end if;
if Nkind (N) = N_Subtype_Indication
or else not Is_Overloaded (N)
then
return
Covers (Typ, Etype (N))
-- Ada 2005 (AI-345): The context may be a synchronized interface.
-- If the type is already frozen use the corresponding_record
-- to check whether it is a proper descendant.
or else
(Is_Record_Type (Typ)
and then Is_Concurrent_Type (Etype (N))
and then Present (Corresponding_Record_Type (Etype (N)))
and then Covers (Typ, Corresponding_Record_Type (Etype (N))))
or else
(Is_Concurrent_Type (Typ)
and then Is_Record_Type (Etype (N))
and then Present (Corresponding_Record_Type (Typ))
and then Covers (Corresponding_Record_Type (Typ), Etype (N)))
or else
(not Is_Tagged_Type (Typ)
and then Ekind (Typ) /= E_Anonymous_Access_Type
and then Covers (Etype (N), Typ))
or else
(Nkind (N) = N_Integer_Literal
and then Present (Find_Aspect (Typ, Aspect_Integer_Literal)))
or else
(Nkind (N) = N_Real_Literal
and then Present (Find_Aspect (Typ, Aspect_Real_Literal)))
or else
(Nkind (N) = N_String_Literal
and then Present (Find_Aspect (Typ, Aspect_String_Literal)));
-- Overloaded case
else
Get_First_Interp (N, I, It);
while Present (It.Typ) loop
if (Covers (Typ, It.Typ)
and then
(Scope (It.Nam) /= Standard_Standard
or else not Is_Invisible_Operator (N, Base_Type (Typ))))
-- Ada 2005 (AI-345)
or else
(Is_Concurrent_Type (It.Typ)
and then Present (Corresponding_Record_Type
(Etype (It.Typ)))
and then Covers (Typ, Corresponding_Record_Type
(Etype (It.Typ))))
or else (not Is_Tagged_Type (Typ)
and then Ekind (Typ) /= E_Anonymous_Access_Type
and then Covers (It.Typ, Typ))
then
return True;
end if;
Get_Next_Interp (I, It);
end loop;
return False;
end if;
end Has_Compatible_Type;
---------------------
-- Has_Abstract_Op --
---------------------
function Has_Abstract_Op
(N : Node_Id;
Typ : Entity_Id) return Entity_Id
is
I : Interp_Index;
It : Interp;
begin
if Is_Overloaded (N) then
Get_First_Interp (N, I, It);
while Present (It.Nam) loop
if Present (It.Abstract_Op)
and then Etype (It.Abstract_Op) = Typ
then
return It.Abstract_Op;
end if;
Get_Next_Interp (I, It);
end loop;
end if;
return Empty;
end Has_Abstract_Op;
----------
-- Hash --
----------
function Hash (N : Node_Id) return Header_Num is
begin
return Header_Num (N mod Header_Max);
end Hash;
--------------
-- Hides_Op --
--------------
function Hides_Op (F : Entity_Id; Op : Entity_Id) return Boolean is
Btyp : constant Entity_Id := Base_Type (Etype (First_Formal (F)));
begin
return Operator_Matches_Spec (Op, F)
and then (In_Open_Scopes (Scope (F))
or else Scope (F) = Scope (Btyp)
or else (not In_Open_Scopes (Scope (Btyp))
and then not In_Use (Btyp)
and then not In_Use (Scope (Btyp))));
end Hides_Op;
------------------------
-- Init_Interp_Tables --
------------------------
procedure Init_Interp_Tables is
begin
All_Interp.Init;
Interp_Map.Reset;
end Init_Interp_Tables;
-----------------------------------
-- Interface_Present_In_Ancestor --
-----------------------------------
function Interface_Present_In_Ancestor
(Typ : Entity_Id;
Iface : Entity_Id) return Boolean
is
Target_Typ : Entity_Id;
Iface_Typ : Entity_Id;
function Iface_Present_In_Ancestor (Typ : Entity_Id) return Boolean;
-- Returns True if Typ or some ancestor of Typ implements Iface
-------------------------------
-- Iface_Present_In_Ancestor --
-------------------------------
function Iface_Present_In_Ancestor (Typ : Entity_Id) return Boolean is
E : Entity_Id;
AI : Entity_Id;
Elmt : Elmt_Id;
begin
if Typ = Iface_Typ then
return True;
end if;
-- Handle private types
if Present (Full_View (Typ))
and then not Is_Concurrent_Type (Full_View (Typ))
then
E := Full_View (Typ);
else
E := Typ;
end if;
loop
if Present (Interfaces (E))
and then not Is_Empty_Elmt_List (Interfaces (E))
then
Elmt := First_Elmt (Interfaces (E));
while Present (Elmt) loop
AI := Node (Elmt);
if AI = Iface_Typ or else Is_Ancestor (Iface_Typ, AI) then
return True;
end if;
Next_Elmt (Elmt);
end loop;
end if;
exit when Etype (E) = E
-- Handle private types
or else (Present (Full_View (Etype (E)))
and then Full_View (Etype (E)) = E);
-- Check if the current type is a direct derivation of the
-- interface
if Etype (E) = Iface_Typ then
return True;
end if;
-- Climb to the immediate ancestor handling private types
if Present (Full_View (Etype (E))) then
E := Full_View (Etype (E));
else
E := Etype (E);
end if;
end loop;
return False;
end Iface_Present_In_Ancestor;
-- Start of processing for Interface_Present_In_Ancestor
begin
-- Iface might be a class-wide subtype, so we have to apply Base_Type
if Is_Class_Wide_Type (Iface) then
Iface_Typ := Etype (Base_Type (Iface));
else
Iface_Typ := Iface;
end if;
-- Handle subtypes
Iface_Typ := Base_Type (Iface_Typ);
if Is_Access_Type (Typ) then
Target_Typ := Etype (Directly_Designated_Type (Typ));
else
Target_Typ := Typ;
end if;
if Is_Concurrent_Record_Type (Target_Typ) then
Target_Typ := Corresponding_Concurrent_Type (Target_Typ);
end if;
Target_Typ := Base_Type (Target_Typ);
-- In case of concurrent types we can't use the Corresponding Record_Typ
-- to look for the interface because it is built by the expander (and
-- hence it is not always available). For this reason we traverse the
-- list of interfaces (available in the parent of the concurrent type)
if Is_Concurrent_Type (Target_Typ) then
if Present (Interface_List (Parent (Target_Typ))) then
declare
AI : Node_Id;
begin
AI := First (Interface_List (Parent (Target_Typ)));
-- The progenitor itself may be a subtype of an interface type.
while Present (AI) loop
if Etype (AI) = Iface_Typ
or else Base_Type (Etype (AI)) = Iface_Typ
then
return True;
elsif Present (Interfaces (Etype (AI)))
and then Iface_Present_In_Ancestor (Etype (AI))
then
return True;
end if;
Next (AI);
end loop;
end;
end if;
return False;
end if;
if Is_Class_Wide_Type (Target_Typ) then
Target_Typ := Etype (Target_Typ);
end if;
if Ekind (Target_Typ) = E_Incomplete_Type then
-- We must have either a full view or a nonlimited view of the type
-- to locate the list of ancestors.
if Present (Full_View (Target_Typ)) then
Target_Typ := Full_View (Target_Typ);
else
-- In a spec expression or in an expression function, the use of
-- an incomplete type is legal; legality of the conversion will be
-- checked at freeze point of related entity.
if In_Spec_Expression then
return True;
else
pragma Assert (Present (Non_Limited_View (Target_Typ)));
Target_Typ := Non_Limited_View (Target_Typ);
end if;
end if;
-- Protect the front end against previously detected errors
if Ekind (Target_Typ) = E_Incomplete_Type then
return False;
end if;
end if;
return Iface_Present_In_Ancestor (Target_Typ);
end Interface_Present_In_Ancestor;
---------------------
-- Intersect_Types --
---------------------
function Intersect_Types (L, R : Node_Id) return Entity_Id is
Index : Interp_Index;
It : Interp;
Typ : Entity_Id;
function Check_Right_Argument (T : Entity_Id) return Entity_Id;
-- Find interpretation of right arg that has type compatible with T
--------------------------
-- Check_Right_Argument --
--------------------------
function Check_Right_Argument (T : Entity_Id) return Entity_Id is
Index : Interp_Index;
It : Interp;
T2 : Entity_Id;
begin
if not Is_Overloaded (R) then
return Specific_Type (T, Etype (R));
else
Get_First_Interp (R, Index, It);
loop
T2 := Specific_Type (T, It.Typ);
if T2 /= Any_Type then
return T2;
end if;
Get_Next_Interp (Index, It);
exit when No (It.Typ);
end loop;
return Any_Type;
end if;
end Check_Right_Argument;
-- Start of processing for Intersect_Types
begin
if Etype (L) = Any_Type or else Etype (R) = Any_Type then
return Any_Type;
end if;
if not Is_Overloaded (L) then
Typ := Check_Right_Argument (Etype (L));
else
Typ := Any_Type;
Get_First_Interp (L, Index, It);
while Present (It.Typ) loop
Typ := Check_Right_Argument (It.Typ);
exit when Typ /= Any_Type;
Get_Next_Interp (Index, It);
end loop;
end if;
-- If Typ is Any_Type, it means no compatible pair of types was found
if Typ = Any_Type then
if Nkind (Parent (L)) in N_Op then
Error_Msg_N ("incompatible types for operator", Parent (L));
elsif Nkind (Parent (L)) = N_Range then
Error_Msg_N ("incompatible types given in constraint", Parent (L));
-- Ada 2005 (AI-251): Complete the error notification
elsif Is_Class_Wide_Type (Etype (R))
and then Is_Interface (Etype (Class_Wide_Type (Etype (R))))
then
Error_Msg_NE ("(Ada 2005) does not implement interface }",
L, Etype (Class_Wide_Type (Etype (R))));
-- Specialize message if one operand is a limited view, a priori
-- unrelated to all other types.
elsif From_Limited_With (Etype (R)) then
Error_Msg_NE ("limited view of& not compatible with context",
R, Etype (R));
elsif From_Limited_With (Etype (L)) then
Error_Msg_NE ("limited view of& not compatible with context",
L, Etype (L));
else
Error_Msg_N ("incompatible types", Parent (L));
end if;
end if;
return Typ;
end Intersect_Types;
-----------------------
-- In_Generic_Actual --
-----------------------
function In_Generic_Actual (Exp : Node_Id) return Boolean is
Par : constant Node_Id := Parent (Exp);
begin
if No (Par) then
return False;
elsif Nkind (Par) in N_Declaration then
return
Nkind (Par) = N_Object_Declaration
and then Present (Corresponding_Generic_Association (Par));
elsif Nkind (Par) = N_Object_Renaming_Declaration then
return Present (Corresponding_Generic_Association (Par));
elsif Nkind (Par) in N_Statement_Other_Than_Procedure_Call then
return False;
else
return In_Generic_Actual (Par);
end if;
end In_Generic_Actual;
-----------------
-- Is_Ancestor --
-----------------
function Is_Ancestor
(T1 : Entity_Id;
T2 : Entity_Id;
Use_Full_View : Boolean := False) return Boolean
is
BT1 : Entity_Id;
BT2 : Entity_Id;
Par : Entity_Id;
begin
BT1 := Base_Type (T1);
BT2 := Base_Type (T2);
-- Handle underlying view of records with unknown discriminants using
-- the original entity that motivated the construction of this
-- underlying record view (see Build_Derived_Private_Type).
if Is_Underlying_Record_View (BT1) then
BT1 := Underlying_Record_View (BT1);
end if;
if Is_Underlying_Record_View (BT2) then
BT2 := Underlying_Record_View (BT2);
end if;
if BT1 = BT2 then
return True;
-- The predicate must look past privacy
elsif Is_Private_Type (T1)
and then Present (Full_View (T1))
and then BT2 = Base_Type (Full_View (T1))
then
return True;
elsif Is_Private_Type (T2)
and then Present (Full_View (T2))
and then BT1 = Base_Type (Full_View (T2))
then
return True;
else
-- Obtain the parent of the base type of T2 (use the full view if
-- allowed).
if Use_Full_View
and then Is_Private_Type (BT2)
and then Present (Full_View (BT2))
then
-- No climbing needed if its full view is the root type
if Full_View (BT2) = Root_Type (Full_View (BT2)) then
return False;
end if;
Par := Etype (Full_View (BT2));
else
Par := Etype (BT2);
end if;
loop
-- If there was a error on the type declaration, do not recurse
if Error_Posted (Par) then
return False;
elsif BT1 = Base_Type (Par)
or else (Is_Private_Type (T1)
and then Present (Full_View (T1))
and then Base_Type (Par) = Base_Type (Full_View (T1)))
then
return True;
elsif Is_Private_Type (Par)
and then Present (Full_View (Par))
and then Full_View (Par) = BT1
then
return True;
-- Root type found
elsif Par = Root_Type (Par) then
return False;
-- Continue climbing
else
-- Use the full-view of private types (if allowed). Guard
-- against infinite loops when full view has same type as
-- parent, as can happen with interface extensions.
if Use_Full_View
and then Is_Private_Type (Par)
and then Present (Full_View (Par))
and then Par /= Etype (Full_View (Par))
then
Par := Etype (Full_View (Par));
else
Par := Etype (Par);
end if;
end if;
end loop;
end if;
end Is_Ancestor;
---------------------------
-- Is_Invisible_Operator --
---------------------------
function Is_Invisible_Operator
(N : Node_Id;
T : Entity_Id) return Boolean
is
Orig_Node : constant Node_Id := Original_Node (N);
begin
if Nkind (N) not in N_Op then
return False;
elsif not Comes_From_Source (N) then
return False;
elsif No (Universal_Interpretation (Right_Opnd (N))) then
return False;
elsif Nkind (N) in N_Binary_Op
and then No (Universal_Interpretation (Left_Opnd (N)))
then
return False;
else
return Is_Numeric_Type (T)
and then not In_Open_Scopes (Scope (T))
and then not Is_Potentially_Use_Visible (T)
and then not In_Use (T)
and then not In_Use (Scope (T))
and then
(Nkind (Orig_Node) /= N_Function_Call
or else Nkind (Name (Orig_Node)) /= N_Expanded_Name
or else Entity (Prefix (Name (Orig_Node))) /= Scope (T))
and then not In_Instance;
end if;
end Is_Invisible_Operator;
--------------------
-- Is_Progenitor --
--------------------
function Is_Progenitor
(Iface : Entity_Id;
Typ : Entity_Id) return Boolean
is
begin
return Implements_Interface (Typ, Iface, Exclude_Parents => True);
end Is_Progenitor;
-------------------
-- Is_Subtype_Of --
-------------------
function Is_Subtype_Of (T1 : Entity_Id; T2 : Entity_Id) return Boolean is
S : Entity_Id;
begin
S := Ancestor_Subtype (T1);
while Present (S) loop
if S = T2 then
return True;
else
S := Ancestor_Subtype (S);
end if;
end loop;
return False;
end Is_Subtype_Of;
------------------
-- List_Interps --
------------------
procedure List_Interps (Nam : Node_Id; Err : Node_Id) is
Index : Interp_Index;
It : Interp;
begin
Get_First_Interp (Nam, Index, It);
while Present (It.Nam) loop
if Scope (It.Nam) = Standard_Standard
and then Scope (It.Typ) /= Standard_Standard
then
Error_Msg_Sloc := Sloc (Parent (It.Typ));
Error_Msg_NE ("\\& (inherited) declared#!", Err, It.Nam);
else
Error_Msg_Sloc := Sloc (It.Nam);
Error_Msg_NE ("\\& declared#!", Err, It.Nam);
end if;
Get_Next_Interp (Index, It);
end loop;
end List_Interps;
-----------------
-- New_Interps --
-----------------
procedure New_Interps (N : Node_Id) is
begin
All_Interp.Append (No_Interp);
-- Add or rewrite the existing node
Last_Overloaded := N;
Interp_Map.Set (N, All_Interp.Last);
Set_Is_Overloaded (N, True);
end New_Interps;
---------------------------
-- Operator_Matches_Spec --
---------------------------
function Operator_Matches_Spec (Op, New_S : Entity_Id) return Boolean is
New_First_F : constant Entity_Id := First_Formal (New_S);
Op_Name : constant Name_Id := Chars (Op);
T : constant Entity_Id := Etype (New_S);
New_F : Entity_Id;
Num : Nat;
Old_F : Entity_Id;
T1 : Entity_Id;
T2 : Entity_Id;
begin
-- To verify that a predefined operator matches a given signature, do a
-- case analysis of the operator classes. Function can have one or two
-- formals and must have the proper result type.
New_F := New_First_F;
Old_F := First_Formal (Op);
Num := 0;
while Present (New_F) and then Present (Old_F) loop
Num := Num + 1;
Next_Formal (New_F);
Next_Formal (Old_F);
end loop;
-- Definite mismatch if different number of parameters
if Present (Old_F) or else Present (New_F) then
return False;
-- Unary operators
elsif Num = 1 then
T1 := Etype (New_First_F);
if Op_Name in Name_Op_Subtract | Name_Op_Add | Name_Op_Abs then
return Base_Type (T1) = Base_Type (T)
and then Is_Numeric_Type (T);
elsif Op_Name = Name_Op_Not then
return Base_Type (T1) = Base_Type (T)
and then Valid_Boolean_Arg (Base_Type (T));
else
return False;
end if;
-- Binary operators
else
T1 := Etype (New_First_F);
T2 := Etype (Next_Formal (New_First_F));
if Op_Name in Name_Op_And | Name_Op_Or | Name_Op_Xor then
return Base_Type (T1) = Base_Type (T2)
and then Base_Type (T1) = Base_Type (T)
and then Valid_Boolean_Arg (Base_Type (T));
elsif Op_Name in Name_Op_Eq | Name_Op_Ne then
return Base_Type (T1) = Base_Type (T2)
and then not Is_Limited_Type (T1)
and then Is_Boolean_Type (T);
elsif Op_Name in Name_Op_Lt | Name_Op_Le | Name_Op_Gt | Name_Op_Ge
then
return Base_Type (T1) = Base_Type (T2)
and then Valid_Comparison_Arg (T1)
and then Is_Boolean_Type (T);
elsif Op_Name in Name_Op_Add | Name_Op_Subtract then
return Base_Type (T1) = Base_Type (T2)
and then Base_Type (T1) = Base_Type (T)
and then Is_Numeric_Type (T);
-- For division and multiplication, a user-defined function does not
-- match the predefined universal_fixed operation, except in Ada 83.
elsif Op_Name = Name_Op_Divide then
return (Base_Type (T1) = Base_Type (T2)
and then Base_Type (T1) = Base_Type (T)
and then Is_Numeric_Type (T)
and then (not Is_Fixed_Point_Type (T)
or else Ada_Version = Ada_83))
-- Mixed_Mode operations on fixed-point types
or else (Base_Type (T1) = Base_Type (T)
and then Base_Type (T2) = Base_Type (Standard_Integer)
and then Is_Fixed_Point_Type (T))
-- A user defined operator can also match (and hide) a mixed
-- operation on universal literals.
or else (Is_Integer_Type (T2)
and then Is_Floating_Point_Type (T1)
and then Base_Type (T1) = Base_Type (T));
elsif Op_Name = Name_Op_Multiply then
return (Base_Type (T1) = Base_Type (T2)
and then Base_Type (T1) = Base_Type (T)
and then Is_Numeric_Type (T)
and then (not Is_Fixed_Point_Type (T)
or else Ada_Version = Ada_83))
-- Mixed_Mode operations on fixed-point types
or else (Base_Type (T1) = Base_Type (T)
and then Base_Type (T2) = Base_Type (Standard_Integer)
and then Is_Fixed_Point_Type (T))
or else (Base_Type (T2) = Base_Type (T)
and then Base_Type (T1) = Base_Type (Standard_Integer)
and then Is_Fixed_Point_Type (T))
or else (Is_Integer_Type (T2)
and then Is_Floating_Point_Type (T1)
and then Base_Type (T1) = Base_Type (T))
or else (Is_Integer_Type (T1)
and then Is_Floating_Point_Type (T2)
and then Base_Type (T2) = Base_Type (T));
elsif Op_Name in Name_Op_Mod | Name_Op_Rem then
return Base_Type (T1) = Base_Type (T2)
and then Base_Type (T1) = Base_Type (T)
and then Is_Integer_Type (T);
elsif Op_Name = Name_Op_Expon then
return Base_Type (T1) = Base_Type (T)
and then Is_Numeric_Type (T)
and then Base_Type (T2) = Base_Type (Standard_Integer);
elsif Op_Name = Name_Op_Concat then
return Is_Array_Type (T)
and then (Base_Type (T) = Base_Type (Etype (Op)))
and then (Base_Type (T1) = Base_Type (T)
or else
Base_Type (T1) = Base_Type (Component_Type (T)))
and then (Base_Type (T2) = Base_Type (T)
or else
Base_Type (T2) = Base_Type (Component_Type (T)));
else
return False;
end if;
end if;
end Operator_Matches_Spec;
-------------------
-- Remove_Interp --
-------------------
procedure Remove_Interp (I : in out Interp_Index) is
II : Interp_Index;
begin
-- Find end of interp list and copy downward to erase the discarded one
II := I + 1;
while Present (All_Interp.Table (II).Typ) loop
II := II + 1;
end loop;
for J in I + 1 .. II loop
All_Interp.Table (J - 1) := All_Interp.Table (J);
end loop;
-- Back up interp index to insure that iterator will pick up next
-- available interpretation.
I := I - 1;
end Remove_Interp;
------------------
-- Save_Interps --
------------------
procedure Save_Interps (Old_N : Node_Id; New_N : Node_Id) is
Old_Ind : Interp_Index;
O_N : Node_Id;
begin
if Is_Overloaded (Old_N) then
Set_Is_Overloaded (New_N);
if Nkind (Old_N) = N_Selected_Component
and then Is_Overloaded (Selector_Name (Old_N))
then
O_N := Selector_Name (Old_N);
else
O_N := Old_N;
end if;
Old_Ind := Interp_Map.Get (O_N);
pragma Assert (Old_Ind >= 0);
New_Interps (New_N);
Interp_Map.Set (New_N, Old_Ind);
end if;
end Save_Interps;
-------------------
-- Specific_Type --
-------------------
function Specific_Type (Typ_1, Typ_2 : Entity_Id) return Entity_Id is
T1 : constant Entity_Id := Available_View (Typ_1);
T2 : constant Entity_Id := Available_View (Typ_2);
B1 : constant Entity_Id := Base_Type (T1);
B2 : constant Entity_Id := Base_Type (T2);
function Is_Remote_Access (T : Entity_Id) return Boolean;
-- Check whether T is the equivalent type of a remote access type.
-- If distribution is enabled, T is a legal context for Null.
----------------------
-- Is_Remote_Access --
----------------------
function Is_Remote_Access (T : Entity_Id) return Boolean is
begin
return Is_Record_Type (T)
and then (Is_Remote_Call_Interface (T)
or else Is_Remote_Types (T))
and then Present (Corresponding_Remote_Type (T))
and then Is_Access_Type (Corresponding_Remote_Type (T));
end Is_Remote_Access;
-- Start of processing for Specific_Type
begin
if T1 = Any_Type or else T2 = Any_Type then
return Any_Type;
end if;
if B1 = B2 then
return B1;
elsif (T1 = Universal_Integer and then Is_Integer_Type (T2))
or else (T1 = Universal_Real and then Is_Real_Type (T2))
or else (T1 = Universal_Fixed and then Is_Fixed_Point_Type (T2))
or else (T1 = Any_Fixed and then Is_Fixed_Point_Type (T2))
then
return B2;
elsif (T2 = Universal_Integer and then Is_Integer_Type (T1))
or else (T2 = Universal_Real and then Is_Real_Type (T1))
or else (T2 = Universal_Fixed and then Is_Fixed_Point_Type (T1))
or else (T2 = Any_Fixed and then Is_Fixed_Point_Type (T1))
then
return B1;
elsif T2 = Any_String and then Is_String_Type (T1) then
return B1;
elsif T1 = Any_String and then Is_String_Type (T2) then
return B2;
elsif T2 = Any_Character and then Is_Character_Type (T1) then
return B1;
elsif T1 = Any_Character and then Is_Character_Type (T2) then
return B2;
elsif T1 = Any_Access
and then (Is_Access_Type (T2) or else Is_Remote_Access (T2))
then
return T2;
elsif T2 = Any_Access
and then (Is_Access_Type (T1) or else Is_Remote_Access (T1))
then
return T1;
-- In an instance, the specific type may have a private view. Use full
-- view to check legality.
elsif T2 = Any_Access
and then Is_Private_Type (T1)
and then Present (Full_View (T1))
and then Is_Access_Type (Full_View (T1))
and then In_Instance
then
return T1;
elsif T2 = Any_Composite and then Is_Aggregate_Type (T1) then
return T1;
elsif T1 = Any_Composite and then Is_Aggregate_Type (T2) then
return T2;
elsif T1 = Any_Modular and then Is_Modular_Integer_Type (T2) then
return T2;
elsif T2 = Any_Modular and then Is_Modular_Integer_Type (T1) then
return T1;
-- ----------------------------------------------------------
-- Special cases for equality operators (all other predefined
-- operators can never apply to tagged types)
-- ----------------------------------------------------------
-- Ada 2005 (AI-251): T1 and T2 are class-wide types, and T2 is an
-- interface
elsif Is_Class_Wide_Type (T1)
and then Is_Class_Wide_Type (T2)
and then Is_Interface (Etype (T2))
then
return T1;
-- Ada 2005 (AI-251): T1 is a concrete type that implements the
-- class-wide interface T2
elsif Is_Class_Wide_Type (T2)
and then Is_Interface (Etype (T2))
and then Interface_Present_In_Ancestor (Typ => T1,
Iface => Etype (T2))
then
return T1;
elsif Is_Class_Wide_Type (T1)
and then Is_Ancestor (Root_Type (T1), T2)
then
return T1;
elsif Is_Class_Wide_Type (T2)
and then Is_Ancestor (Root_Type (T2), T1)
then
return T2;
elsif Is_Access_Type (T1)
and then Is_Access_Type (T2)
and then Is_Class_Wide_Type (Designated_Type (T1))
and then not Is_Class_Wide_Type (Designated_Type (T2))
and then
Is_Ancestor (Root_Type (Designated_Type (T1)), Designated_Type (T2))
then
return T1;
elsif Is_Access_Type (T1)
and then Is_Access_Type (T2)
and then Is_Class_Wide_Type (Designated_Type (T2))
and then not Is_Class_Wide_Type (Designated_Type (T1))
and then
Is_Ancestor (Root_Type (Designated_Type (T2)), Designated_Type (T1))
then
return T2;
elsif Ekind (B1) in E_Access_Subprogram_Type
| E_Access_Protected_Subprogram_Type
and then Ekind (Designated_Type (B1)) /= E_Subprogram_Type
and then Is_Access_Type (T2)
then
return T2;
elsif Ekind (B2) in E_Access_Subprogram_Type
| E_Access_Protected_Subprogram_Type
and then Ekind (Designated_Type (B2)) /= E_Subprogram_Type
and then Is_Access_Type (T1)
then
return T1;
elsif Ekind (T1) in E_Allocator_Type | E_Access_Attribute_Type
and then Is_Access_Type (T2)
then
return T2;
elsif Ekind (T2) in E_Allocator_Type | E_Access_Attribute_Type
and then Is_Access_Type (T1)
then
return T1;
-- Ada 2005 (AI-230): Support the following operators:
-- function "=" (L, R : universal_access) return Boolean;
-- function "/=" (L, R : universal_access) return Boolean;
-- Pool-specific access types (E_Access_Type) are not covered by these
-- operators because of the legality rule of 4.5.2(9.2): "The operands
-- of the equality operators for universal_access shall be convertible
-- to one another (see 4.6)". For example, considering the type decla-
-- ration "type P is access Integer" and an anonymous access to Integer,
-- P is convertible to "access Integer" by 4.6 (24.11-24.15), but there
-- is no rule in 4.6 that allows "access Integer" to be converted to P.
-- Note that this does not preclude one operand to be a pool-specific
-- access type, as a previous version of this code enforced.
elsif Ada_Version >= Ada_2005 then
if Is_Anonymous_Access_Type (T1)
and then Is_Access_Type (T2)
then
return T1;
elsif Is_Anonymous_Access_Type (T2)
and then Is_Access_Type (T1)
then
return T2;
end if;
end if;
-- If none of the above cases applies, types are not compatible
return Any_Type;
end Specific_Type;
---------------------
-- Set_Abstract_Op --
---------------------
procedure Set_Abstract_Op (I : Interp_Index; V : Entity_Id) is
begin
All_Interp.Table (I).Abstract_Op := V;
end Set_Abstract_Op;
-----------------------
-- Valid_Boolean_Arg --
-----------------------
-- In addition to booleans and arrays of booleans, we must include
-- aggregates as valid boolean arguments, because in the first pass of
-- resolution their components are not examined. If it turns out not to be
-- an aggregate of booleans, this will be diagnosed in Resolve.
-- Any_Composite must be checked for prior to the array type checks because
-- Any_Composite does not have any associated indexes.
function Valid_Boolean_Arg (T : Entity_Id) return Boolean is
begin
if Is_Boolean_Type (T)
or else Is_Modular_Integer_Type (T)
or else T = Universal_Integer
or else T = Any_Composite
then
return True;
elsif Is_Array_Type (T)
and then T /= Any_String
and then Number_Dimensions (T) = 1
and then Is_Boolean_Type (Component_Type (T))
and then
((not Is_Private_Composite (T) and then not Is_Limited_Composite (T))
or else In_Instance
or else Available_Full_View_Of_Component (T))
then
return True;
else
return False;
end if;
end Valid_Boolean_Arg;
--------------------------
-- Valid_Comparison_Arg --
--------------------------
function Valid_Comparison_Arg (T : Entity_Id) return Boolean is
begin
if T = Any_Composite then
return False;
elsif Is_Discrete_Type (T)
or else Is_Real_Type (T)
then
return True;
elsif Is_Array_Type (T)
and then Number_Dimensions (T) = 1
and then Is_Discrete_Type (Component_Type (T))
and then (not Is_Private_Composite (T) or else In_Instance)
and then (not Is_Limited_Composite (T) or else In_Instance)
then
return True;
elsif Is_Array_Type (T)
and then Number_Dimensions (T) = 1
and then Is_Discrete_Type (Component_Type (T))
and then Available_Full_View_Of_Component (T)
then
return True;
elsif Is_String_Type (T) then
return True;
else
return False;
end if;
end Valid_Comparison_Arg;
------------------
-- Write_Interp --
------------------
procedure Write_Interp (It : Interp) is
begin
Write_Str ("Nam: ");
Print_Tree_Node (It.Nam);
Write_Str ("Typ: ");
Print_Tree_Node (It.Typ);
Write_Str ("Abstract_Op: ");
Print_Tree_Node (It.Abstract_Op);
end Write_Interp;
---------------------
-- Write_Overloads --
---------------------
procedure Write_Overloads (N : Node_Id) is
I : Interp_Index;
It : Interp;
Nam : Entity_Id;
begin
Write_Str ("Overloads: ");
Print_Node_Briefly (N);
if not Is_Overloaded (N) then
if Is_Entity_Name (N) then
Write_Line ("Non-overloaded entity ");
Write_Entity_Info (Entity (N), " ");
end if;
elsif Nkind (N) not in N_Has_Entity then
Get_First_Interp (N, I, It);
while Present (It.Nam) loop
Write_Int (Int (It.Typ));
Write_Str (" ");
Write_Name (Chars (It.Typ));
Write_Eol;
Get_Next_Interp (I, It);
end loop;
else
Get_First_Interp (N, I, It);
Write_Line ("Overloaded entity ");
Write_Line (" Name Type Abstract Op");
Write_Line ("===============================================");
Nam := It.Nam;
while Present (Nam) loop
Write_Int (Int (Nam));
Write_Str (" ");
Write_Name (Chars (Nam));
Write_Str (" ");
Write_Int (Int (It.Typ));
Write_Str (" ");
Write_Name (Chars (It.Typ));
if Present (It.Abstract_Op) then
Write_Str (" ");
Write_Int (Int (It.Abstract_Op));
Write_Str (" ");
Write_Name (Chars (It.Abstract_Op));
end if;
Write_Eol;
Get_Next_Interp (I, It);
Nam := It.Nam;
end loop;
end if;
end Write_Overloads;
end Sem_Type;