@@ -120,6 +120,29 @@ impl<'a> AnalyzeContext<'a> {
120120 self . matcher ( ) . is_possible ( types, ttyp)
121121 }
122122
123+ pub fn common_type ( & self , typ1 : BaseType < ' a > , typ2 : BaseType < ' a > ) -> Option < BaseType < ' a > > {
124+ if typ1. id ( ) == typ2. id ( ) {
125+ Some ( typ1)
126+ } else if typ1. is_universal_of ( typ2) {
127+ Some ( typ2)
128+ } else if typ2. is_universal_of ( typ1) {
129+ Some ( typ1)
130+ } else {
131+ None
132+ }
133+ }
134+
135+ pub fn common_types (
136+ & self ,
137+ types : FnvHashSet < BaseType < ' a > > ,
138+ typ : BaseType < ' a > ,
139+ ) -> FnvHashSet < BaseType < ' a > > {
140+ types
141+ . into_iter ( )
142+ . filter_map ( |t| self . common_type ( t, typ) )
143+ . collect ( )
144+ }
145+
123146 pub fn can_be_target_type ( & self , typ : TypeEnt < ' a > , ttyp : BaseType < ' a > ) -> bool {
124147 self . matcher ( ) . can_be_target_type ( typ, ttyp)
125148 }
@@ -235,20 +258,44 @@ impl<'a> AnalyzeContext<'a> {
235258 if candidates. len ( ) > 1 {
236259 self . matcher ( )
237260 . disambiguate_op_by_arguments ( & mut candidates, & operand_types) ;
261+ }
238262
239- if candidates. len ( ) > 1 && ttyp. is_some ( ) {
240- self . matcher ( )
241- . disambiguate_op_by_return_type ( & mut candidates, ttyp) ;
263+ if candidates. len ( ) > 1 && ttyp. is_some ( ) {
264+ self . matcher ( )
265+ . disambiguate_op_by_return_type ( & mut candidates, ttyp) ;
266+ }
242267
243- if candidates. len ( ) > 1 {
244- self . matcher_no_implicit ( )
245- . disambiguate_op_by_arguments ( & mut candidates, & operand_types) ;
268+ // Try to further disambiguate by removing implicit universal casts
269+ if candidates. len ( ) > 1 {
270+ let return_types: FnvHashSet < _ > = candidates
271+ . iter ( )
272+ . map ( |c| c. return_type ( ) . unwrap ( ) . base ( ) )
273+ . collect ( ) ;
246274
247- if candidates. len ( ) > 1 {
248- self . matcher_no_implicit ( )
249- . disambiguate_op_by_return_type ( & mut candidates, ttyp) ;
275+ if return_types. len ( ) == 1 {
276+ self . matcher_no_implicit ( )
277+ . disambiguate_op_by_arguments ( & mut candidates, & operand_types) ;
278+ }
279+ }
280+
281+ if candidates. len ( ) > 1 {
282+ if ttyp. is_some ( ) {
283+ self . matcher_no_implicit ( )
284+ . disambiguate_op_by_return_type ( & mut candidates, ttyp) ;
285+ } else {
286+ let return_types: FnvHashSet < _ > = candidates
287+ . iter ( )
288+ . map ( |c| c. return_type ( ) . unwrap ( ) . base ( ) )
289+ . collect ( ) ;
290+
291+ // Remove INTEGER if universal integer is a candidate
292+ candidates. retain ( |cand| {
293+ if let Some ( univ) = self . as_universal ( cand. return_type ( ) . unwrap ( ) . base ( ) ) {
294+ !return_types. contains ( & univ)
295+ } else {
296+ true
250297 }
251- }
298+ } )
252299 }
253300 }
254301
@@ -268,6 +315,14 @@ impl<'a> AnalyzeContext<'a> {
268315 }
269316 }
270317
318+ fn as_universal ( & self , typ : BaseType < ' a > ) -> Option < BaseType < ' a > > {
319+ match typ. kind ( ) {
320+ Type :: Integer => Some ( self . universal_integer ( ) ) ,
321+ Type :: Real => Some ( self . universal_real ( ) ) ,
322+ _ => None ,
323+ }
324+ }
325+
271326 pub fn operator_type (
272327 & self ,
273328 scope : & Scope < ' a > ,
@@ -734,7 +789,7 @@ impl<'a> AnalyzeContext<'a> {
734789 & self ,
735790 scope : & Scope < ' a > ,
736791 array_type : TypeEnt < ' a > ,
737- index_type : Option < TypeEnt < ' a > > ,
792+ index_type : Option < BaseType < ' a > > ,
738793 elem_type : TypeEnt < ' a > ,
739794 assoc : & mut ElementAssociation ,
740795 diagnostics : & mut dyn DiagnosticHandler ,
@@ -760,7 +815,7 @@ impl<'a> AnalyzeContext<'a> {
760815 if let Some ( index_type) = index_type {
761816 self . expr_with_ttyp (
762817 scope,
763- index_type,
818+ index_type. into ( ) ,
764819 & index_expr. pos ,
765820 & mut index_expr. item ,
766821 diagnostics,
@@ -778,7 +833,7 @@ impl<'a> AnalyzeContext<'a> {
778833 if let Some ( index_type) = index_type {
779834 self . analyze_discrete_range_with_target_type (
780835 scope,
781- index_type,
836+ index_type. into ( ) ,
782837 drange,
783838 diagnostics,
784839 ) ?;
@@ -1145,4 +1200,40 @@ constant c0 : rec_t := (0, 1);
11451200 Some ( ExpressionType :: Unambiguous ( test. lookup_type( "boolean" ) ) )
11461201 ) ;
11471202 }
1203+
1204+ #[ test]
1205+ fn does_not_remove_universal_candidates_when_return_types_differ ( ) {
1206+ let test = TestSetup :: new ( ) ;
1207+ test. declarative_part (
1208+ "
1209+ function \" +\" (a : integer; b : character) return character;
1210+ function \" +\" (a : integer; b : character) return integer;
1211+ " ,
1212+ ) ;
1213+
1214+ let code = test. snippet ( "0 + 'c'" ) ;
1215+ assert_eq ! (
1216+ test. expr_type( & code, & mut NoDiagnostics ) ,
1217+ Some ( ExpressionType :: Ambiguous (
1218+ vec![
1219+ test. lookup_type( "integer" ) . base( ) ,
1220+ test. lookup_type( "character" ) . base( )
1221+ ]
1222+ . into_iter( )
1223+ . collect( )
1224+ ) )
1225+ ) ;
1226+ }
1227+
1228+ #[ test]
1229+ fn universal_expression_is_not_ambiguous ( ) {
1230+ let test = TestSetup :: new ( ) ;
1231+ let code = test. snippet ( "-1" ) ;
1232+ assert_eq ! (
1233+ test. expr_type( & code, & mut NoDiagnostics ) ,
1234+ Some ( ExpressionType :: Unambiguous (
1235+ test. ctx( ) . universal_integer( ) . into( )
1236+ ) )
1237+ ) ;
1238+ }
11481239}
0 commit comments