@@ -533,6 +533,93 @@ impl<'a> AnalyzeContext<'a> {
533533 self . expr_pos_with_ttyp ( scope, target_type, & expr. pos , & mut expr. item , diagnostics)
534534 }
535535
536+ fn implicit_bool_types ( & self , scope : & Scope < ' a > , pos : & SrcPos ) -> FnvHashSet < BaseType < ' a > > {
537+ if let Ok ( NamedEntities :: Overloaded ( overloaded) ) =
538+ scope. lookup ( pos, & Designator :: OperatorSymbol ( Operator :: QueQue ) )
539+ {
540+ overloaded
541+ . entities ( )
542+ . filter_map ( |ent| ent. formals ( ) . nth ( 0 ) . map ( |typ| typ. type_mark ( ) . base ( ) ) )
543+ . collect ( )
544+ } else {
545+ FnvHashSet :: default ( )
546+ }
547+ }
548+
549+ /// An expression that is either boolean or implicitly boolean via ?? operator
550+ pub fn boolean_expr (
551+ & self ,
552+ scope : & Scope < ' a > ,
553+ expr : & mut WithPos < Expression > ,
554+ diagnostics : & mut dyn DiagnosticHandler ,
555+ ) -> FatalResult {
556+ if let Some ( types) = as_fatal ( self . expr_type ( scope, expr, diagnostics) ) ? {
557+ match types {
558+ ExpressionType :: Unambiguous ( typ) => {
559+ if typ. base ( ) != self . boolean ( ) . base ( ) {
560+ let implicit_bools = self . implicit_bool_types ( scope, & expr. pos ) ;
561+ if !implicit_bools. contains ( & typ. base ( ) ) {
562+ diagnostics. error (
563+ & expr. pos ,
564+ format ! (
565+ "{} cannot be implictly converted to {}. Operator ?? is not defined for this type." ,
566+ typ. describe( ) ,
567+ self . boolean( ) . describe( )
568+ ) ,
569+ ) ;
570+ }
571+ }
572+ }
573+ ExpressionType :: Ambiguous ( types) => {
574+ if types. contains ( & self . boolean ( ) . base ( ) ) {
575+ self . expr_with_ttyp ( scope, self . boolean ( ) , expr, diagnostics) ?;
576+ } else {
577+ let implicit_bool_types: FnvHashSet < _ > = self
578+ . implicit_bool_types ( scope, & expr. pos )
579+ . intersection ( & types)
580+ . cloned ( )
581+ . collect ( ) ;
582+
583+ match implicit_bool_types. len ( ) . cmp ( & 1 ) {
584+ std:: cmp:: Ordering :: Equal => {
585+ let typ: TypeEnt = types. into_iter ( ) . next ( ) . unwrap ( ) . into ( ) ;
586+ self . expr_with_ttyp ( scope, typ, expr, diagnostics) ?;
587+ }
588+ std:: cmp:: Ordering :: Greater => {
589+ let mut diag = Diagnostic :: error (
590+ & expr. pos ,
591+ "Ambiguous use of implicit boolean conversion ??" ,
592+ ) ;
593+ diag. add_type_candididates ( "Could be" , implicit_bool_types) ;
594+ diagnostics. push ( diag) ;
595+ }
596+
597+ std:: cmp:: Ordering :: Less => {
598+ let mut diag = Diagnostic :: error (
599+ & expr. pos ,
600+ format ! (
601+ "Cannot disambiguate expression to {}" ,
602+ self . boolean( ) . describe( )
603+ ) ,
604+ ) ;
605+ diag. add_type_candididates (
606+ "Implicit boolean conversion operator ?? is not defined for" ,
607+ types,
608+ ) ;
609+ diagnostics. push ( diag) ;
610+ }
611+ }
612+ }
613+ }
614+ ExpressionType :: String | ExpressionType :: Null | ExpressionType :: Aggregate => {
615+ self . expr_with_ttyp ( scope, self . boolean ( ) , expr, diagnostics) ?;
616+ }
617+ }
618+ }
619+
620+ Ok ( ( ) )
621+ }
622+
536623 /// Returns true if the name actually matches the target type
537624 /// None if it was uncertain
538625 pub fn expr_pos_with_ttyp (
0 commit comments