@@ -66,7 +66,8 @@ type parameter).
66
66
67
67
*/
68
68
69
- import astconv :: { ast_conv, ast_ty_to_ty, ast_region_to_region} ;
69
+ import astconv :: { ast_conv, ast_path_to_ty, ast_ty_to_ty} ;
70
+ import astconv :: { ast_region_to_region} ;
70
71
import collect :: { methods} ; // ccx.to_ty()
71
72
import middle:: ty:: { tv_vid, vid} ;
72
73
import regionmanip :: { replace_bound_regions_in_fn_ty, region_of} ;
@@ -76,6 +77,8 @@ import syntax::ast::ty_i;
76
77
import typeck:: infer:: { unify_methods} ; // infcx.set()
77
78
import typeck:: infer:: { resolve_type, force_tvar} ;
78
79
80
+ import std:: map:: str_hash;
81
+
79
82
type fn_ctxt_ =
80
83
// var_bindings, locals and next_var_id are shared
81
84
// with any nested functions that capture the environment
@@ -1628,8 +1631,136 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1628
1631
}
1629
1632
}
1630
1633
}
1631
- ast::expr_struct(*) {
1632
- fail ~" XXX structs";
1634
+ ast::expr_struct(path, fields) {
1635
+ // Resolve the path.
1636
+ let class_id;
1637
+ alt tcx.def_map.find(id) {
1638
+ some(ast::def_class(type_def_id)) => {
1639
+ class_id = type_def_id;
1640
+ }
1641
+ _ => {
1642
+ tcx.sess.span_bug(path.span, ~"structure constructor does \
1643
+ not name a structure type " ) ;
1644
+ }
1645
+ }
1646
+
1647
+ // Look up the number of type parameters and the raw type, and
1648
+ // determine whether the class is region-parameterized.
1649
+ let type_parameter_count, region_parameterized, raw_type;
1650
+ if class_id. crate == ast:: local_crate {
1651
+ region_parameterized =
1652
+ tcx. region_paramd_items . contains_key ( class_id. node ) ;
1653
+ alt tcx. items . find ( class_id. node ) {
1654
+ some ( ast_map:: node_item ( @{
1655
+ node: ast:: item_class ( type_parameters, _, _, _, _) ,
1656
+ _
1657
+ } , _) ) => {
1658
+
1659
+ type_parameter_count = type_parameters. len ( ) ;
1660
+
1661
+ let self_region;
1662
+ if region_parameterized {
1663
+ self_region = some ( ty:: re_bound ( ty:: br_self) ) ;
1664
+ } else {
1665
+ self_region = none;
1666
+ }
1667
+
1668
+ raw_type = ty:: mk_class ( tcx, class_id, {
1669
+ self_r: self_region,
1670
+ self_ty: none,
1671
+ tps: ty:: ty_params_to_tys ( tcx, type_parameters)
1672
+ } ) ;
1673
+ }
1674
+ _ => {
1675
+ tcx. sess . span_bug ( expr. span ,
1676
+ ~"resolve didn' t map this to a class") ;
1677
+ }
1678
+ }
1679
+ } else {
1680
+ let item_type = ty:: lookup_item_type ( tcx, class_id) ;
1681
+ type_parameter_count = ( * item_type. bounds ) . len ( ) ;
1682
+ region_parameterized = item_type. rp ;
1683
+ raw_type = item_type. ty ;
1684
+ }
1685
+
1686
+ // Generate the struct type.
1687
+ let self_region;
1688
+ if region_parameterized {
1689
+ self_region = some ( fcx. infcx . next_region_var_nb ( ) ) ;
1690
+ } else {
1691
+ self_region = none;
1692
+ }
1693
+
1694
+ let type_parameters = fcx. infcx . next_ty_vars ( type_parameter_count) ;
1695
+ let substitutions = {
1696
+ self_r: self_region,
1697
+ self_ty: none,
1698
+ tps: type_parameters
1699
+ } ;
1700
+
1701
+ let struct_type = ty:: subst ( tcx, substitutions, raw_type) ;
1702
+
1703
+ // Look up the class fields and build up a map.
1704
+ let class_fields = ty:: lookup_class_fields ( tcx, class_id) ;
1705
+ let class_field_map = str_hash ( ) ;
1706
+ let mut fields_found = 0 ;
1707
+ for class_fields. each |field| {
1708
+ // XXX: Check visibility here.
1709
+ class_field_map. insert ( * field. ident , ( field. id , false ) ) ;
1710
+ }
1711
+
1712
+ // Typecheck each field.
1713
+ for fields. each |field| {
1714
+ alt class_field_map. find( * field. node. ident) {
1715
+ none => {
1716
+ tcx. sess . span_err ( field. span ,
1717
+ #fmt ( "structure has no field named \
1718
+ field named `%s`",
1719
+ * field. node . ident ) ) ;
1720
+ }
1721
+ some ( ( _, true ) ) => {
1722
+ tcx. sess . span_err ( field. span ,
1723
+ #fmt ( "field `%s` specified more than \
1724
+ once",
1725
+ * field. node . ident ) ) ;
1726
+ }
1727
+ some ( ( field_id, false ) ) => {
1728
+ let expected_field_type =
1729
+ ty:: lookup_field_type ( tcx, class_id, field_id,
1730
+ substitutions) ;
1731
+ bot |= check_expr ( fcx,
1732
+ field. node . expr ,
1733
+ some ( expected_field_type) ) ;
1734
+ fields_found += 1 ;
1735
+ }
1736
+ }
1737
+ }
1738
+
1739
+ // Make sure the programmer specified all the fields.
1740
+ assert fields_found <= class_fields. len ( ) ;
1741
+ if fields_found < class_fields. len ( ) {
1742
+ let mut missing_fields = ~[ ] ;
1743
+ for class_fields. each |class_field| {
1744
+ let name = * class_field. ident ;
1745
+ let ( _, seen) = class_field_map. get ( name) ;
1746
+ if !seen {
1747
+ vec:: push ( missing_fields,
1748
+ ~"`" + name + ~"`") ;
1749
+ }
1750
+ }
1751
+
1752
+ tcx. sess . span_err ( expr. span ,
1753
+ #fmt ( "missing field%s: %s" ,
1754
+ if missing_fields. len ( ) == 1 {
1755
+ ~""
1756
+ } else {
1757
+ ~"s"
1758
+ } ,
1759
+ str:: connect ( missing_fields, ~", ")));
1760
+ }
1761
+
1762
+ // Write in the resulting type.
1763
+ fcx.write_ty(id, struct_type);
1633
1764
}
1634
1765
ast::expr_field(base, field, tys) {
1635
1766
bot = check_field(fcx, expr, false, base, field, tys);
0 commit comments