@@ -559,6 +559,15 @@ fn valid_range_bounds(ccx: @crate_ctxt, from: @ast::expr, to: @ast::expr)
559
559
const_eval:: compare_lit_exprs ( ccx. tcx , from, to) <= 0
560
560
}
561
561
562
+ type pat_ctxt = {
563
+ fcx : @fn_ctxt ,
564
+ map : pat_id_map ,
565
+ alt_region : ty:: region ,
566
+ block_region : ty:: region ,
567
+ /* Equal to either alt_region or block_region. */
568
+ pat_region : ty:: region
569
+ } ;
570
+
562
571
// Helper for the other universally_quantify_*() routines. Extracts the bound
563
572
// regions from bound_tys and then replaces those same regions with fresh
564
573
// variables in `sty`, returning the resulting type.
@@ -664,6 +673,223 @@ fn replace_bound_regions(
664
673
}
665
674
}
666
675
676
+ fn check_pat_variant ( pcx : pat_ctxt , pat : @ast:: pat , path : @ast:: path ,
677
+ subpats : option < [ @ast:: pat ] > , expected : ty:: t ) {
678
+
679
+ // Typecheck the path.
680
+ let fcx = pcx. fcx ;
681
+ let tcx = pcx. fcx . ccx . tcx ;
682
+
683
+ // Lookup the enum and variant def ids:
684
+ let v_def = lookup_def ( pcx. fcx , path. span , pat. id ) ;
685
+ let v_def_ids = ast_util:: variant_def_ids ( v_def) ;
686
+
687
+ // Assign the pattern the type of the *enum*, not the variant.
688
+ let enum_tpt = ty:: lookup_item_type ( tcx, v_def_ids. enm ) ;
689
+ instantiate_path ( pcx. fcx , path, enum_tpt, pat. span , pat. id ) ;
690
+
691
+ // Take the enum type params out of `expected`.
692
+ alt structure_of ( pcx. fcx , pat. span , expected) {
693
+ ty:: ty_enum ( _, expected_substs) {
694
+ // check that the type of the value being matched is a subtype
695
+ // of the type of the pattern:
696
+ let pat_ty = fcx. node_ty ( pat. id ) ;
697
+ demand:: suptype ( fcx, pat. span , pat_ty, expected) ;
698
+
699
+ // Get the expected types of the arguments.
700
+ let arg_types = {
701
+ let vinfo =
702
+ ty:: enum_variant_with_id (
703
+ tcx, v_def_ids. enm , v_def_ids. var ) ;
704
+ vinfo. args . map { |t| ty:: subst ( tcx, expected_substs, t) }
705
+ } ;
706
+ let arg_len = arg_types. len ( ) , subpats_len = alt subpats {
707
+ none { arg_len }
708
+ some ( ps) { ps. len ( ) } } ;
709
+ if arg_len > 0 u {
710
+ // N-ary variant.
711
+ if arg_len != subpats_len {
712
+ let s = #fmt[ "this pattern has %u field%s, but the \
713
+ corresponding variant has %u field%s",
714
+ subpats_len,
715
+ if subpats_len == 1 u { "" } else { "s" } ,
716
+ arg_len,
717
+ if arg_len == 1 u { "" } else { "s" } ] ;
718
+ tcx. sess . span_fatal ( pat. span , s) ;
719
+ }
720
+
721
+ option:: iter ( subpats) { |pats|
722
+ vec:: iter2 ( pats, arg_types) { |subpat, arg_ty|
723
+ check_pat ( pcx, subpat, arg_ty) ;
724
+ }
725
+ } ;
726
+ } else if subpats_len > 0 u {
727
+ tcx. sess . span_fatal
728
+ ( pat. span , #fmt[ "this pattern has %u field%s, \
729
+ but the corresponding variant has no fields",
730
+ subpats_len,
731
+ if subpats_len == 1 u { "" }
732
+ else { "s" } ] ) ;
733
+ }
734
+ }
735
+ _ {
736
+ tcx. sess . span_fatal
737
+ ( pat. span ,
738
+ #fmt[ "mismatched types: expected enum but found `%s`" ,
739
+ fcx. ty_to_str ( expected) ] ) ;
740
+ }
741
+ }
742
+ }
743
+
744
+ // Pattern checking is top-down rather than bottom-up so that bindings get
745
+ // their types immediately.
746
+ fn check_pat ( pcx : pat_ctxt , pat : @ast:: pat , expected : ty:: t ) {
747
+ let fcx = pcx. fcx ;
748
+ let tcx = pcx. fcx . ccx . tcx ;
749
+ alt pat. node {
750
+ ast:: pat_wild {
751
+ fcx. write_ty ( pat. id , expected) ;
752
+ }
753
+ ast:: pat_lit ( lt) {
754
+ check_expr_with ( pcx. fcx , lt, expected) ;
755
+ fcx. write_ty ( pat. id , fcx. expr_ty ( lt) ) ;
756
+ }
757
+ ast:: pat_range ( begin, end) {
758
+ check_expr_with ( pcx. fcx , begin, expected) ;
759
+ check_expr_with ( pcx. fcx , end, expected) ;
760
+ let b_ty = resolve_type_vars_if_possible ( pcx. fcx ,
761
+ fcx. expr_ty ( begin) ) ;
762
+ if !require_same_types (
763
+ tcx, pat. span , b_ty,
764
+ resolve_type_vars_if_possible (
765
+ pcx. fcx , fcx. expr_ty ( end) ) ,
766
+ { || "mismatched types in range" } ) {
767
+ // no-op
768
+ } else if !ty:: type_is_numeric ( b_ty) {
769
+ tcx. sess . span_err ( pat. span , "non-numeric type used in range" ) ;
770
+ } else if !valid_range_bounds ( pcx. fcx . ccx , begin, end) {
771
+ tcx. sess . span_err ( begin. span , "lower range bound must be less \
772
+ than upper") ;
773
+ }
774
+ fcx. write_ty ( pat. id , b_ty) ;
775
+ }
776
+ ast:: pat_ident ( name, sub) if !pat_is_variant ( tcx. def_map , pat) {
777
+ let vid = lookup_local ( pcx. fcx , pat. span , pat. id ) ;
778
+ let mut typ = ty:: mk_var ( tcx, vid) ;
779
+ demand:: suptype ( pcx. fcx , pat. span , expected, typ) ;
780
+ let canon_id = pcx. map . get ( pat_util:: path_to_ident ( name) ) ;
781
+ if canon_id != pat. id {
782
+ let tv_id = lookup_local ( pcx. fcx , pat. span , canon_id) ;
783
+ let ct = ty:: mk_var ( tcx, tv_id) ;
784
+ demand:: suptype ( pcx. fcx , pat. span , ct, typ) ;
785
+ }
786
+ fcx. write_ty ( pat. id , typ) ;
787
+ alt sub {
788
+ some( p) { check_pat ( pcx, p, expected) ; }
789
+ _ { }
790
+ }
791
+ }
792
+ ast:: pat_ident ( path, c) {
793
+ check_pat_variant ( pcx, pat, path, some ( [ ] ) , expected) ;
794
+ }
795
+ ast:: pat_enum ( path, subpats) {
796
+ check_pat_variant ( pcx, pat, path, subpats, expected) ;
797
+ }
798
+ ast:: pat_rec ( fields, etc) {
799
+ let ex_fields = alt structure_of ( pcx. fcx , pat. span , expected) {
800
+ ty:: ty_rec ( fields) { fields }
801
+ _ {
802
+ tcx. sess . span_fatal
803
+ ( pat. span ,
804
+ #fmt[ "mismatched types: expected `%s` but found record" ,
805
+ fcx. ty_to_str ( expected) ] ) ;
806
+ }
807
+ } ;
808
+ let f_count = vec:: len ( fields) ;
809
+ let ex_f_count = vec:: len ( ex_fields) ;
810
+ if ex_f_count < f_count || !etc && ex_f_count > f_count {
811
+ tcx. sess . span_fatal
812
+ ( pat. span , #fmt[ "mismatched types: expected a record \
813
+ with %u fields, found one with %u \
814
+ fields",
815
+ ex_f_count, f_count] ) ;
816
+ }
817
+ fn matches ( name : str , f : ty:: field ) -> bool {
818
+ ret str:: eq ( name, f. ident ) ;
819
+ }
820
+ for fields. each { |f|
821
+ alt vec:: find( ex_fields, bind matches( f. ident, _) ) {
822
+ some( field) {
823
+ check_pat( pcx, f. pat, field. mt. ty) ;
824
+ }
825
+ none {
826
+ tcx. sess . span_fatal ( pat. span ,
827
+ #fmt[ "mismatched types: did not \
828
+ expect a record with a field `%s`",
829
+ f. ident ] ) ;
830
+ }
831
+ }
832
+ }
833
+ fcx. write_ty ( pat. id , expected) ;
834
+ }
835
+ ast:: pat_tup ( elts) {
836
+ let ex_elts = alt structure_of ( pcx. fcx , pat. span , expected) {
837
+ ty:: ty_tup ( elts) { elts }
838
+ _ {
839
+ tcx. sess . span_fatal
840
+ ( pat. span ,
841
+ #fmt[ "mismatched types: expected `%s`, found tuple" ,
842
+ fcx. ty_to_str ( expected) ] ) ;
843
+ }
844
+ } ;
845
+ let e_count = vec:: len ( elts) ;
846
+ if e_count != vec:: len ( ex_elts) {
847
+ tcx. sess . span_fatal
848
+ ( pat. span , #fmt[ "mismatched types: expected a tuple \
849
+ with %u fields, found one with %u \
850
+ fields", vec:: len ( ex_elts) , e_count] ) ;
851
+ }
852
+ let mut i = 0 u;
853
+ for elts. each { |elt|
854
+ check_pat( pcx, elt, ex_elts[ i] ) ;
855
+ i += 1 u;
856
+ }
857
+
858
+ fcx. write_ty ( pat. id , expected) ;
859
+ }
860
+ ast:: pat_box ( inner) {
861
+ alt structure_of ( pcx. fcx , pat. span , expected) {
862
+ ty:: ty_box ( e_inner) {
863
+ check_pat ( pcx, inner, e_inner. ty ) ;
864
+ fcx. write_ty ( pat. id , expected) ;
865
+ }
866
+ _ {
867
+ tcx. sess . span_fatal (
868
+ pat. span ,
869
+ "mismatched types: expected `" +
870
+ pcx. fcx . ty_to_str ( expected) +
871
+ "` found box" ) ;
872
+ }
873
+ }
874
+ }
875
+ ast:: pat_uniq ( inner) {
876
+ alt structure_of ( pcx. fcx , pat. span , expected) {
877
+ ty:: ty_uniq ( e_inner) {
878
+ check_pat ( pcx, inner, e_inner. ty ) ;
879
+ fcx. write_ty ( pat. id , expected) ;
880
+ }
881
+ _ {
882
+ tcx. sess . span_fatal (
883
+ pat. span ,
884
+ "mismatched types: expected `" +
885
+ pcx. fcx . ty_to_str ( expected) +
886
+ "` found uniq" ) ;
887
+ }
888
+ }
889
+ }
890
+ }
891
+ }
892
+
667
893
fn check_expr_with ( fcx : @fn_ctxt , expr : @ast:: expr , expected : ty:: t ) -> bool {
668
894
check_expr ( fcx, expr, some ( expected) )
669
895
}
@@ -1644,7 +1870,38 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1644
1870
bot = !may_break( body) ;
1645
1871
}
1646
1872
ast:: expr_alt( discrim, arms, _) {
1647
- alt:: check_alt( expr, discrim, arms) ;
1873
+ let pattern_ty = fcx. next_ty_var( ) ;
1874
+ bot = check_expr_with( fcx, discrim, pattern_ty) ;
1875
+
1876
+ // Typecheck the patterns first, so that we get types for all the
1877
+ // bindings.
1878
+ //let pattern_ty = fcx.expr_ty(discrim);
1879
+ for arms. each { |arm|
1880
+ let pcx = {
1881
+ fcx : fcx,
1882
+ map : pat_id_map( tcx. def_map, arm. pats[ 0 ] ) ,
1883
+ alt_region : ty:: re_scope( expr. id) ,
1884
+ block_region : ty:: re_scope( arm. body. node. id) ,
1885
+ pat_region : ty:: re_scope( expr. id)
1886
+ } ;
1887
+
1888
+ for arm. pats. each { |p| check_pat( pcx, p, pattern_ty) ; }
1889
+ }
1890
+ // Now typecheck the blocks.
1891
+ let mut result_ty = fcx. next_ty_var( ) ;
1892
+ let mut arm_non_bot = false ;
1893
+ for arms. each { |arm|
1894
+ alt arm. guard {
1895
+ some( e) { check_expr_with( fcx, e, ty:: mk_bool( tcx) ) ; }
1896
+ none { }
1897
+ }
1898
+ if !check_block( fcx, arm. body) { arm_non_bot = true ; }
1899
+ let bty = fcx. node_ty( arm. body. node. id) ;
1900
+ demand:: suptype( fcx, arm. body. span, result_ty, bty) ;
1901
+ }
1902
+ bot |= !arm_non_bot;
1903
+ if !arm_non_bot { result_ty = ty:: mk_bot( tcx) ; }
1904
+ fcx. write_ty( id, result_ty) ;
1648
1905
}
1649
1906
ast:: expr_fn( proto, decl, body, cap_clause) {
1650
1907
check_expr_fn( fcx, expr, proto, decl, body, false , expected) ;
0 commit comments