@@ -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,16 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
330330 & mut self ,
331331 pattern : UntypedPattern ,
332332 subject : & TypedExpr ,
333+ subject_type_override : 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 (
338+ pattern,
339+ subject_type,
340+ subject_variable,
341+ subject_type_override,
342+ ) ;
337343 self . register_variables ( ) ;
338344 typed_pattern
339345 }
@@ -453,7 +459,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
453459 . into_iter ( )
454460 . map ( |option| {
455461 analyse:: infer_bit_array_option ( option, |value, type_| {
456- Ok ( self . unify ( value, type_, None ) )
462+ Ok ( self . unify ( value, type_, None , None ) )
457463 } )
458464 } )
459465 . try_collect ( )
@@ -529,7 +535,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
529535 _ => segment_type,
530536 } ;
531537
532- let typed_value = self . unify ( * segment. value , type_. clone ( ) , None ) ;
538+ let typed_value = self . unify ( * segment. value , type_. clone ( ) , None , None ) ;
533539
534540 match & typed_value {
535541 // We can't directly match on the contents of a `Box`, so we must
@@ -586,6 +592,18 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
586592 // in the inner scope, we can infer that the `some_wibble` variable is the `Wibble` variant
587593 //
588594 subject_variable : Option < EcoString > ,
595+ // An optional type annotation provided for the pattern.
596+ //
597+ // Example:
598+ // ```gleam
599+ // let assert [first, ..rest]: List(String) = numbers
600+ // ```
601+ //
602+ // We pass `List(String)` annotation down so sub-patterns know
603+ // that `first` must be a `String`. We still check `numbers`
604+ // against its real inferred type and emit a mismatch if it is, say,
605+ // `List(Int)`.
606+ annotation_type : Option < Arc < Type > > ,
589607 ) -> TypedPattern {
590608 match pattern {
591609 Pattern :: Discard { name, location, .. } => {
@@ -595,7 +613,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
595613 . discarded_names
596614 . insert ( name. clone ( ) , location) ;
597615 Pattern :: Discard {
598- type_,
616+ type_ : annotation_type . unwrap_or_else ( || type_ . clone ( ) ) ,
599617 name,
600618 location,
601619 }
@@ -609,10 +627,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
609627 origin,
610628 ..
611629 } => {
612- 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 ( ) ) ;
613632
614633 Pattern :: Variable {
615- type_,
634+ type_ : variable_type ,
616635 name,
617636 location,
618637 origin,
@@ -691,17 +710,24 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
691710 pattern,
692711 location,
693712 } => {
694- let pattern = self . unify ( * pattern, type_, subject_variable) ;
713+ let pattern_annotation = annotation_type. clone ( ) ;
714+ let pattern = self . unify (
715+ * pattern,
716+ type_. clone ( ) ,
717+ subject_variable,
718+ pattern_annotation,
719+ ) ;
695720
696721 if pattern. is_discard ( ) {
697722 self . problems . warning ( Warning :: UnusedDiscardPattern {
698723 location,
699724 name : name. clone ( ) ,
700725 } ) ;
701726 }
727+ let assigned_type = annotation_type. unwrap_or_else ( || pattern. type_ ( ) . clone ( ) ) ;
702728 self . insert_variable (
703729 & name,
704- pattern . type_ ( ) . clone ( ) ,
730+ assigned_type . clone ( ) ,
705731 location,
706732 VariableOrigin {
707733 syntax : VariableSyntax :: AssignmentPattern ,
@@ -766,28 +792,53 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
766792 self . environment ,
767793 ) {
768794 Some ( arguments) => {
769- let type_ = arguments
795+ let element_type = arguments
770796 . first ( )
771797 . expect ( "Failed to get type argument of List" )
772798 . clone ( ) ;
799+ let list_type = list ( element_type. clone ( ) ) ;
800+ let annotation_element_type = annotation_type. as_ref ( ) . and_then ( |annotation| {
801+ annotation
802+ . get_app_arguments (
803+ Publicity :: Public ,
804+ PRELUDE_PACKAGE_NAME ,
805+ PRELUDE_MODULE_NAME ,
806+ "List" ,
807+ 1 ,
808+ self . environment ,
809+ )
810+ . and_then ( |arguments| arguments. into_iter ( ) . next ( ) )
811+ } ) ;
773812 let elements = elements
774813 . into_iter ( )
775- . map ( |element| self . unify ( element, type_. clone ( ) , None ) )
814+ . map ( |element| {
815+ self . unify (
816+ element,
817+ element_type. clone ( ) ,
818+ None ,
819+ annotation_element_type. clone ( ) ,
820+ )
821+ } )
776822 . collect ( ) ;
777- let type_ = list ( type_) ;
778823
779824 let tail = tail. map ( |tail| {
825+ let tail_annotation = annotation_type. clone ( ) ;
780826 Box :: new ( TailPattern {
781827 location : tail. location ,
782- pattern : self . unify ( tail. pattern , type_. clone ( ) , None ) ,
828+ pattern : self . unify (
829+ tail. pattern ,
830+ list_type. clone ( ) ,
831+ None ,
832+ tail_annotation,
833+ ) ,
783834 } )
784835 } ) ;
785836
786837 Pattern :: List {
787838 location,
788839 elements,
789840 tail,
790- type_,
841+ type_ : list_type ,
791842 }
792843 }
793844
@@ -819,10 +870,22 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
819870 return Pattern :: Invalid { location, type_ } ;
820871 }
821872
873+ let annotation_elements = annotation_type. as_ref ( ) . and_then ( |annotation| {
874+ match collapse_links ( annotation. clone ( ) ) . deref ( ) {
875+ Type :: Tuple { elements } => Some ( elements. clone ( ) ) ,
876+ _ => None ,
877+ }
878+ } ) ;
822879 let elements = elements
823880 . into_iter ( )
824881 . zip ( type_elements)
825- . map ( |( pattern, type_) | self . unify ( pattern, type_. clone ( ) , None ) )
882+ . enumerate ( )
883+ . map ( |( index, ( pattern, type_) ) | {
884+ let annotation = annotation_elements
885+ . as_ref ( )
886+ . and_then ( |elements| elements. get ( index) . cloned ( ) ) ;
887+ self . unify ( pattern, type_. clone ( ) , None , annotation)
888+ } )
826889 . collect ( ) ;
827890 Pattern :: Tuple { elements, location }
828891 }
@@ -832,10 +895,22 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
832895 . map ( |_| self . environment . new_unbound_var ( ) )
833896 . collect ( ) ;
834897 self . unify_types ( tuple ( elements_types. clone ( ) ) , type_, location) ;
898+ let annotation_elements = annotation_type. as_ref ( ) . and_then ( |annotation| {
899+ match collapse_links ( annotation. clone ( ) ) . deref ( ) {
900+ Type :: Tuple { elements } => Some ( elements. clone ( ) ) ,
901+ _ => None ,
902+ }
903+ } ) ;
835904 let elements = elements
836905 . into_iter ( )
837906 . zip ( elements_types)
838- . map ( |( pattern, type_) | self . unify ( pattern, type_, None ) )
907+ . enumerate ( )
908+ . map ( |( index, ( pattern, type_) ) | {
909+ let annotation = annotation_elements
910+ . as_ref ( )
911+ . and_then ( |elements| elements. get ( index) . cloned ( ) ) ;
912+ self . unify ( pattern, type_, None , annotation)
913+ } )
839914 . collect ( ) ;
840915 Pattern :: Tuple { elements, location }
841916 }
@@ -1213,7 +1288,8 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
12131288 . cloned ( )
12141289 . unwrap_or_else ( || self . environment . new_unbound_var ( ) ) ;
12151290
1216- let value = self . unify ( value, type_, None ) ;
1291+ let annotation = Some ( type_. clone ( ) ) ;
1292+ let value = self . unify ( value, type_, None , annotation) ;
12171293 CallArg {
12181294 value,
12191295 location,
0 commit comments