@@ -317,7 +317,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
317317 for ( pattern, subject) in multi_pattern. into_iter ( ) . zip ( subjects) {
318318 let subject_variable = Self :: subject_variable ( subject) ;
319319
320- let pattern = self . unify ( pattern, subject. type_ ( ) , subject_variable) ;
320+ let pattern = self . unify ( pattern, subject. type_ ( ) , subject_variable, None ) ;
321321 typed_multi. push ( pattern) ;
322322 }
323323
@@ -330,10 +330,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
330330 & mut self ,
331331 pattern : UntypedPattern ,
332332 subject : & TypedExpr ,
333+ annotation_type : Option < Arc < Type > > ,
333334 ) -> TypedPattern {
334335 let subject_variable = Self :: subject_variable ( subject) ;
335-
336- let typed_pattern = self . unify ( pattern, subject . type_ ( ) , subject_variable) ;
336+ let subject_type = subject . type_ ( ) ;
337+ let typed_pattern = self . unify ( pattern, subject_type , subject_variable, annotation_type ) ;
337338 self . register_variables ( ) ;
338339 typed_pattern
339340 }
@@ -453,7 +454,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
453454 . into_iter ( )
454455 . map ( |option| {
455456 analyse:: infer_bit_array_option ( option, |value, type_| {
456- Ok ( self . unify ( value, type_, None ) )
457+ Ok ( self . unify ( value, type_, None , None ) )
457458 } )
458459 } )
459460 . try_collect ( )
@@ -529,7 +530,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
529530 _ => segment_type,
530531 } ;
531532
532- let typed_value = self . unify ( * segment. value , type_. clone ( ) , None ) ;
533+ let typed_value = self . unify ( * segment. value , type_. clone ( ) , None , None ) ;
533534
534535 match & typed_value {
535536 // We can't directly match on the contents of a `Box`, so we must
@@ -586,6 +587,18 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
586587 // in the inner scope, we can infer that the `some_wibble` variable is the `Wibble` variant
587588 //
588589 subject_variable : Option < EcoString > ,
590+ // An optional type annotation provided for the pattern.
591+ //
592+ // Example:
593+ // ```gleam
594+ // let assert [first, ..rest]: List(String) = numbers
595+ // ```
596+ //
597+ // We pass `List(String)` annotation down so sub-patterns know
598+ // that `first` must be a `String`. We still check `numbers`
599+ // against its real inferred type and emit a mismatch if it is, say,
600+ // `List(Int)`.
601+ annotation_type : Option < Arc < Type > > ,
589602 ) -> TypedPattern {
590603 match pattern {
591604 Pattern :: Discard { name, location, .. } => {
@@ -595,7 +608,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
595608 . discarded_names
596609 . insert ( name. clone ( ) , location) ;
597610 Pattern :: Discard {
598- type_,
611+ type_ : annotation_type . unwrap_or_else ( || type_ . clone ( ) ) ,
599612 name,
600613 location,
601614 }
@@ -614,10 +627,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
614627 Pattern :: Invalid { location, type_ }
615628 }
616629 _ => {
617- self . insert_variable ( & name, type_. clone ( ) , location, origin. clone ( ) ) ;
630+ let variable_type = annotation_type. unwrap_or_else ( || type_. clone ( ) ) ;
631+ self . insert_variable ( & name, variable_type. clone ( ) , location, origin. clone ( ) ) ;
618632
619633 Pattern :: Variable {
620- type_,
634+ type_ : variable_type ,
621635 name,
622636 location,
623637 origin,
@@ -697,17 +711,24 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
697711 pattern,
698712 location,
699713 } => {
700- let pattern = self . unify ( * pattern, type_, subject_variable) ;
714+ let pattern_annotation = annotation_type. clone ( ) ;
715+ let pattern = self . unify (
716+ * pattern,
717+ type_. clone ( ) ,
718+ subject_variable,
719+ pattern_annotation,
720+ ) ;
701721
702722 if pattern. is_discard ( ) {
703723 self . problems . warning ( Warning :: UnusedDiscardPattern {
704724 location,
705725 name : name. clone ( ) ,
706726 } ) ;
707727 }
728+ let assigned_type = annotation_type. unwrap_or_else ( || pattern. type_ ( ) . clone ( ) ) ;
708729 self . insert_variable (
709730 & name,
710- pattern . type_ ( ) . clone ( ) ,
731+ assigned_type . clone ( ) ,
711732 location,
712733 VariableOrigin {
713734 syntax : VariableSyntax :: AssignmentPattern ,
@@ -780,28 +801,53 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
780801 self . environment ,
781802 ) {
782803 Some ( arguments) => {
783- let type_ = arguments
804+ let element_type = arguments
784805 . first ( )
785806 . expect ( "Failed to get type argument of List" )
786807 . clone ( ) ;
808+ let list_type = list ( element_type. clone ( ) ) ;
809+ let annotation_element_type = annotation_type. as_ref ( ) . and_then ( |annotation| {
810+ annotation
811+ . get_app_arguments (
812+ Publicity :: Public ,
813+ PRELUDE_PACKAGE_NAME ,
814+ PRELUDE_MODULE_NAME ,
815+ "List" ,
816+ 1 ,
817+ self . environment ,
818+ )
819+ . and_then ( |arguments| arguments. into_iter ( ) . next ( ) )
820+ } ) ;
787821 let elements = elements
788822 . into_iter ( )
789- . map ( |element| self . unify ( element, type_. clone ( ) , None ) )
823+ . map ( |element| {
824+ self . unify (
825+ element,
826+ element_type. clone ( ) ,
827+ None ,
828+ annotation_element_type. clone ( ) ,
829+ )
830+ } )
790831 . collect ( ) ;
791- let type_ = list ( type_) ;
792832
793833 let tail = tail. map ( |tail| {
834+ let tail_annotation = annotation_type. clone ( ) ;
794835 Box :: new ( TailPattern {
795836 location : tail. location ,
796- pattern : self . unify ( tail. pattern , type_. clone ( ) , None ) ,
837+ pattern : self . unify (
838+ tail. pattern ,
839+ list_type. clone ( ) ,
840+ None ,
841+ tail_annotation,
842+ ) ,
797843 } )
798844 } ) ;
799845
800846 Pattern :: List {
801847 location,
802848 elements,
803849 tail,
804- type_,
850+ type_ : list_type ,
805851 }
806852 }
807853
@@ -833,10 +879,22 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
833879 return Pattern :: Invalid { location, type_ } ;
834880 }
835881
882+ let annotation_elements = annotation_type. as_ref ( ) . and_then ( |annotation| {
883+ match collapse_links ( annotation. clone ( ) ) . deref ( ) {
884+ Type :: Tuple { elements } => Some ( elements. clone ( ) ) ,
885+ _ => None ,
886+ }
887+ } ) ;
836888 let elements = elements
837889 . into_iter ( )
838890 . zip ( type_elements)
839- . map ( |( pattern, type_) | self . unify ( pattern, type_. clone ( ) , None ) )
891+ . enumerate ( )
892+ . map ( |( index, ( pattern, type_) ) | {
893+ let annotation = annotation_elements
894+ . as_ref ( )
895+ . and_then ( |elements| elements. get ( index) . cloned ( ) ) ;
896+ self . unify ( pattern, type_. clone ( ) , None , annotation)
897+ } )
840898 . collect ( ) ;
841899 Pattern :: Tuple { elements, location }
842900 }
@@ -846,10 +904,22 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
846904 . map ( |_| self . environment . new_unbound_var ( ) )
847905 . collect ( ) ;
848906 self . unify_types ( tuple ( elements_types. clone ( ) ) , type_, location) ;
907+ let annotation_elements = annotation_type. as_ref ( ) . and_then ( |annotation| {
908+ match collapse_links ( annotation. clone ( ) ) . deref ( ) {
909+ Type :: Tuple { elements } => Some ( elements. clone ( ) ) ,
910+ _ => None ,
911+ }
912+ } ) ;
849913 let elements = elements
850914 . into_iter ( )
851915 . zip ( elements_types)
852- . map ( |( pattern, type_) | self . unify ( pattern, type_, None ) )
916+ . enumerate ( )
917+ . map ( |( index, ( pattern, type_) ) | {
918+ let annotation = annotation_elements
919+ . as_ref ( )
920+ . and_then ( |elements| elements. get ( index) . cloned ( ) ) ;
921+ self . unify ( pattern, type_, None , annotation)
922+ } )
853923 . collect ( ) ;
854924 Pattern :: Tuple { elements, location }
855925 }
@@ -1227,7 +1297,8 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
12271297 . cloned ( )
12281298 . unwrap_or_else ( || self . environment . new_unbound_var ( ) ) ;
12291299
1230- let value = self . unify ( value, type_, None ) ;
1300+ let annotation = Some ( type_. clone ( ) ) ;
1301+ let value = self . unify ( value, type_, None , annotation) ;
12311302 CallArg {
12321303 value,
12331304 location,
0 commit comments