@@ -8,8 +8,9 @@ use super::{
88} ;
99use crate :: resolve:: { self , Names , Res } ;
1010use qsc_ast:: ast:: {
11- self , BinOp , Block , Expr , ExprKind , Functor , Ident , Lit , NodeId , Pat , PatKind , Path , PathKind ,
12- QubitInit , QubitInitKind , Spec , Stmt , StmtKind , StringComponent , TernOp , TyKind , UnOp ,
11+ self , BinOp , Block , Expr , ExprKind , FieldAccess , Functor , Ident , Idents , Lit , NodeId , Pat ,
12+ PatKind , Path , PathKind , QubitInit , QubitInitKind , Spec , Stmt , StmtKind , StringComponent ,
13+ TernOp , TyKind , UnOp ,
1314} ;
1415use qsc_data_structures:: span:: Span ;
1516use qsc_hir:: {
@@ -268,16 +269,20 @@ impl<'a> Context<'a> {
268269 }
269270 ExprKind :: Field ( record, name) => {
270271 let record = self . infer_expr ( record) ;
271- let item_ty = self . inferrer . fresh_ty ( TySource :: not_divergent ( expr. span ) ) ;
272- self . inferrer . class (
273- expr. span ,
274- Class :: HasField {
275- record : record. ty ,
276- name : name. name . to_string ( ) ,
277- item : item_ty. clone ( ) ,
278- } ,
279- ) ;
280- self . diverge_if ( record. diverges , converge ( item_ty) )
272+ if let FieldAccess :: Ok ( name) = name {
273+ let item_ty = self . inferrer . fresh_ty ( TySource :: not_divergent ( expr. span ) ) ;
274+ self . inferrer . class (
275+ expr. span ,
276+ Class :: HasField {
277+ record : record. ty ,
278+ name : name. name . to_string ( ) ,
279+ item : item_ty. clone ( ) ,
280+ } ,
281+ ) ;
282+ self . diverge_if ( record. diverges , converge ( item_ty) )
283+ } else {
284+ converge ( Ty :: Err )
285+ }
281286 }
282287 ExprKind :: For ( item, container, body) => {
283288 let item_ty = self . infer_pat ( item) ;
@@ -394,7 +399,7 @@ impl<'a> Context<'a> {
394399 Lit :: String ( _) => converge ( Ty :: Prim ( Prim :: String ) ) ,
395400 } ,
396401 ExprKind :: Paren ( expr) => self . infer_expr ( expr) ,
397- ExprKind :: Path ( PathKind :: Ok ( path) ) => self . infer_path ( expr, path) ,
402+ ExprKind :: Path ( path) => self . infer_path_kind ( expr, path) ,
398403 ExprKind :: Range ( start, step, end) => {
399404 let mut diverges = false ;
400405 for expr in start. iter ( ) . chain ( step) . chain ( end) {
@@ -532,9 +537,7 @@ impl<'a> Context<'a> {
532537 self . typed_holes . push ( ( expr. id , expr. span ) ) ;
533538 converge ( self . inferrer . fresh_ty ( TySource :: not_divergent ( expr. span ) ) )
534539 }
535- ExprKind :: Err
536- | ast:: ExprKind :: Path ( ast:: PathKind :: Err ( _) )
537- | ast:: ExprKind :: Struct ( ast:: PathKind :: Err ( _) , ..) => converge ( Ty :: Err ) ,
540+ ExprKind :: Err | ast:: ExprKind :: Struct ( ast:: PathKind :: Err ( _) , ..) => converge ( Ty :: Err ) ,
538541 } ;
539542
540543 self . record ( expr. id , ty. ty . clone ( ) ) ;
@@ -570,24 +573,23 @@ impl<'a> Context<'a> {
570573 record
571574 }
572575
573- fn infer_path ( & mut self , expr : & Expr , path : & Path ) -> Partial < Ty > {
574- match resolve:: path_as_field_accessor ( self . names , path) {
575- // If the path is a field accessor, we infer the type of first segment
576- // as an expr, and the rest as subsequent fields.
577- Some ( ( first_id, parts) ) => {
578- let record = converge (
579- self . table
580- . terms
581- . get ( first_id)
582- . expect ( "local should have type" )
583- . clone ( ) ,
584- ) ;
585- let ( first, rest) = parts
586- . split_first ( )
587- . expect ( "path should have at least one part" ) ;
588- self . record ( first. id , record. ty . clone ( ) ) ;
589- self . infer_path_parts ( record, rest, expr. span . lo )
576+ fn infer_path_kind ( & mut self , expr : & Expr , path : & PathKind ) -> Partial < Ty > {
577+ match path {
578+ PathKind :: Ok ( path) => self . infer_path ( expr, path) ,
579+ PathKind :: Err ( incomplete_path) => {
580+ if let Some ( incomplete_path) = incomplete_path {
581+ // If this is a field access, infer the fields,
582+ // but leave the whole expression as `Err`.
583+ let _ = self . infer_path_as_field_access ( & incomplete_path. segments , expr) ;
584+ }
585+ converge ( Ty :: Err )
590586 }
587+ }
588+ }
589+
590+ fn infer_path ( & mut self , expr : & Expr , path : & Path ) -> Partial < Ty > {
591+ match self . infer_path_as_field_access ( path, expr) {
592+ Some ( record) => record,
591593 // Otherwise we infer the path as a namespace path.
592594 None => match self . names . get ( path. id ) {
593595 None => converge ( Ty :: Err ) ,
@@ -620,6 +622,31 @@ impl<'a> Context<'a> {
620622 }
621623 }
622624
625+ fn infer_path_as_field_access (
626+ & mut self ,
627+ path : & impl Idents ,
628+ expr : & Expr ,
629+ ) -> Option < Partial < Ty > > {
630+ // If the path is a field accessor, we infer the type of first segment
631+ // as an expr, and the rest as subsequent fields.
632+ if let Some ( ( first_id, parts) ) = resolve:: path_as_field_accessor ( self . names , path) {
633+ let record = converge (
634+ self . table
635+ . terms
636+ . get ( first_id)
637+ . expect ( "local should have type" )
638+ . clone ( ) ,
639+ ) ;
640+ let ( first, rest) = parts
641+ . split_first ( )
642+ . expect ( "path should have at least one part" ) ;
643+ self . record ( first. id , record. ty . clone ( ) ) ;
644+ Some ( self . infer_path_parts ( record, rest, expr. span . lo ) )
645+ } else {
646+ None
647+ }
648+ }
649+
623650 fn infer_hole_tuple < T > (
624651 & mut self ,
625652 hole : fn ( Ty ) -> T ,
0 commit comments