@@ -542,7 +542,7 @@ impl<'a> Analysis<'a> {
542542 & mut self ,
543543 attrs : & Attrs ,
544544 value : & Value ,
545- expect : Type ,
545+ mut expect : Type ,
546546 ) -> AnalysisResult < Type > {
547547 match value {
548548 Value :: Number ( _) => expect. check ( attrs, Type :: Number ) ,
@@ -566,19 +566,22 @@ impl<'a> Analysis<'a> {
566566 }
567567 }
568568
569- this @ Value :: Array ( exprs) => {
569+ Value :: Array ( exprs) => {
570570 if matches ! ( expect, Type :: Unspecified ) {
571- return Ok ( self . project_type ( this) ) ;
571+ for expr in exprs {
572+ expect = self . analyze_expr ( expr, expect) ?;
573+ }
574+
575+ return Ok ( Type :: Array ( Box :: new ( expect) ) ) ;
572576 }
573577
574578 match expect {
575- Type :: Array ( mut types) if exprs. len ( ) == types. len ( ) => {
576- for ( expr, expect) in exprs. iter ( ) . zip ( types. iter_mut ( ) ) {
577- let tmp = mem:: take ( expect) ;
578- * expect = self . analyze_expr ( expr, tmp) ?;
579+ Type :: Array ( mut expect) => {
580+ for expr in exprs {
581+ * expect = self . analyze_expr ( expr, expect. as_ref ( ) . clone ( ) ) ?;
579582 }
580583
581- Ok ( Type :: Array ( types ) )
584+ Ok ( Type :: Array ( expect ) )
582585 }
583586
584587 expect => Err ( AnalysisError :: TypeMismatch (
@@ -590,9 +593,22 @@ impl<'a> Analysis<'a> {
590593 }
591594 }
592595
593- this @ Value :: Record ( fields) => {
596+ Value :: Record ( fields) => {
594597 if matches ! ( expect, Type :: Unspecified ) {
595- return Ok ( self . project_type ( this) ) ;
598+ let mut record = BTreeMap :: new ( ) ;
599+
600+ for field in fields {
601+ record. insert (
602+ field. name . clone ( ) ,
603+ self . analyze_value (
604+ & field. value . attrs ,
605+ & field. value . value ,
606+ Type :: Unspecified ,
607+ ) ?,
608+ ) ;
609+ }
610+
611+ return Ok ( Type :: Record ( record) ) ;
596612 }
597613
598614 match expect {
@@ -692,6 +708,34 @@ impl<'a> Analysis<'a> {
692708 expect. check ( attrs, Type :: Bool )
693709 }
694710
711+ Operator :: Contains => {
712+ let lhs_expect =
713+ self . analyze_expr ( & binary. lhs , Type :: Array ( Box :: new ( Type :: Unspecified ) ) ) ?;
714+
715+ let lhs_assumption = match lhs_expect {
716+ Type :: Array ( inner) => * inner,
717+ other => {
718+ return Err ( AnalysisError :: ExpectArray (
719+ attrs. pos . line ,
720+ attrs. pos . col ,
721+ other,
722+ ) ) ;
723+ }
724+ } ;
725+
726+ let rhs_expect = self . analyze_expr ( & binary. rhs , lhs_assumption. clone ( ) ) ?;
727+
728+ // If the left side didn't have enough type information while the other did,
729+ // we replay another typecheck pass on the left side if the right side was conclusive
730+ if matches ! ( lhs_assumption, Type :: Unspecified )
731+ && !matches ! ( rhs_expect, Type :: Unspecified )
732+ {
733+ self . analyze_expr ( & binary. lhs , Type :: Array ( Box :: new ( rhs_expect) ) ) ?;
734+ }
735+
736+ expect. check ( attrs, Type :: Bool )
737+ }
738+
695739 Operator :: And | Operator :: Or | Operator :: Xor => {
696740 self . analyze_expr ( & binary. lhs , Type :: Bool ) ?;
697741 self . analyze_expr ( & binary. rhs , Type :: Bool ) ?;
@@ -914,7 +958,18 @@ impl<'a> Analysis<'a> {
914958 }
915959 }
916960 Value :: Array ( exprs) => {
917- Type :: Array ( exprs. iter ( ) . map ( |v| self . project_type ( & v. value ) ) . collect ( ) )
961+ let mut project = Type :: Unspecified ;
962+
963+ for expr in exprs {
964+ let tmp = self . project_type ( & expr. value ) ;
965+
966+ if !matches ! ( tmp, Type :: Unspecified ) {
967+ project = tmp;
968+ break ;
969+ }
970+ }
971+
972+ Type :: Array ( Box :: new ( project) )
918973 }
919974 Value :: Record ( fields) => Type :: Record (
920975 fields
@@ -951,7 +1006,8 @@ impl<'a> Analysis<'a> {
9511006 | Operator :: And
9521007 | Operator :: Or
9531008 | Operator :: Xor
954- | Operator :: Not => Type :: Bool ,
1009+ | Operator :: Not
1010+ | Operator :: Contains => Type :: Bool ,
9551011 } ,
9561012 Value :: Unary ( unary) => match unary. operator {
9571013 Operator :: Add | Operator :: Sub => Type :: Number ,
@@ -966,7 +1022,8 @@ impl<'a> Analysis<'a> {
9661022 | Operator :: And
9671023 | Operator :: Or
9681024 | Operator :: Xor
969- | Operator :: Not => unreachable ! ( ) ,
1025+ | Operator :: Not
1026+ | Operator :: Contains => unreachable ! ( ) ,
9701027 } ,
9711028 Value :: Group ( expr) => self . project_type ( & expr. value ) ,
9721029 }
0 commit comments