@@ -1441,6 +1441,136 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1441
1441
return bot;
1442
1442
}
1443
1443
1444
+ fn check_struct_constructor(fcx: @fn_ctxt,
1445
+ id: ast::node_id,
1446
+ span: syntax::codemap::span,
1447
+ class_id: ast::def_id,
1448
+ fields: ~[ast::field],
1449
+ base_expr: Option<@ast::expr>) -> bool {
1450
+ let mut bot = false;
1451
+ let tcx = fcx.ccx.tcx;
1452
+
1453
+ // Look up the number of type parameters and the raw type, and
1454
+ // determine whether the class is region-parameterized.
1455
+ let type_parameter_count, region_parameterized, raw_type;
1456
+ if class_id.crate == ast::local_crate {
1457
+ region_parameterized =
1458
+ tcx.region_paramd_items.find(class_id.node);
1459
+ match tcx.items.find(class_id.node) {
1460
+ Some(ast_map::node_item(@{
1461
+ node: ast::item_class(_, type_parameters),
1462
+ _
1463
+ }, _)) => {
1464
+
1465
+ type_parameter_count = type_parameters.len();
1466
+
1467
+ let self_region =
1468
+ bound_self_region(region_parameterized);
1469
+
1470
+ raw_type = ty::mk_class(tcx, class_id, {
1471
+ self_r: self_region,
1472
+ self_ty: None,
1473
+ tps: ty::ty_params_to_tys(tcx, type_parameters)
1474
+ });
1475
+ }
1476
+ _ => {
1477
+ tcx.sess.span_bug(span,
1478
+ ~" resolve didn' t map this to a class");
1479
+ }
1480
+ }
1481
+ } else {
1482
+ let item_type = ty::lookup_item_type(tcx, class_id);
1483
+ type_parameter_count = (*item_type.bounds).len();
1484
+ region_parameterized = item_type.region_param;
1485
+ raw_type = item_type.ty;
1486
+ }
1487
+
1488
+ // Generate the struct type.
1489
+ let self_region =
1490
+ fcx.region_var_if_parameterized(region_parameterized,
1491
+ span,
1492
+ ty::re_scope(id));
1493
+ let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
1494
+ let substitutions = {
1495
+ self_r: self_region,
1496
+ self_ty: None,
1497
+ tps: type_parameters
1498
+ };
1499
+
1500
+ let struct_type = ty::subst(tcx, &substitutions, raw_type);
1501
+
1502
+ // Look up the class fields and build up a map.
1503
+ let class_fields = ty::lookup_class_fields(tcx, class_id);
1504
+ let class_field_map = HashMap();
1505
+ let mut fields_found = 0;
1506
+ for class_fields.each |field| {
1507
+ // XXX: Check visibility here.
1508
+ class_field_map.insert(field.ident, (field.id, false));
1509
+ }
1510
+
1511
+ // Typecheck each field.
1512
+ for fields.each |field| {
1513
+ match class_field_map.find(field.node.ident) {
1514
+ None => {
1515
+ tcx.sess.span_err(
1516
+ field.span,
1517
+ fmt!(" structure has no field named field named `%s`",
1518
+ tcx. sess. str_of( field. node. ident) ) ) ;
1519
+ }
1520
+ Some ( ( _, true ) ) => {
1521
+ tcx. sess. span_err(
1522
+ field. span,
1523
+ fmt!( "field `%s` specified more than once" ,
1524
+ tcx. sess. str_of( field. node. ident) ) ) ;
1525
+ }
1526
+ Some ( ( field_id, false ) ) => {
1527
+ let expected_field_type =
1528
+ ty:: lookup_field_type( tcx, class_id, field_id,
1529
+ & substitutions) ;
1530
+ bot |= check_expr( fcx,
1531
+ field. node. expr,
1532
+ Some ( expected_field_type) ) ;
1533
+ fields_found += 1 ;
1534
+ }
1535
+ }
1536
+ }
1537
+
1538
+ match base_expr {
1539
+ None => {
1540
+ // Make sure the programmer specified all the fields.
1541
+ assert fields_found <= class_fields. len( ) ;
1542
+ if fields_found < class_fields. len( ) {
1543
+ let mut missing_fields = ~[ ] ;
1544
+ for class_fields. each |class_field| {
1545
+ let name = class_field. ident;
1546
+ let ( _, seen) = class_field_map. get( name) ;
1547
+ if !seen {
1548
+ missing_fields. push(
1549
+ ~"`" + tcx. sess. str_of( name) + ~"`") ;
1550
+ }
1551
+ }
1552
+
1553
+ tcx. sess. span_err( span,
1554
+ fmt!( "missing field%s: %s" ,
1555
+ if missing_fields. len( ) == 1 {
1556
+ ~""
1557
+ } else {
1558
+ ~"s"
1559
+ },
1560
+ str::connect(missing_fields,
1561
+ ~" , ")));
1562
+ }
1563
+ }
1564
+ Some(base_expr) => {
1565
+ // Just check the base expression.
1566
+ check_expr(fcx, base_expr, Some(struct_type));
1567
+ }
1568
+ }
1569
+
1570
+ // Write in the resulting type.
1571
+ fcx.write_ty(id, struct_type);
1572
+ return bot;
1573
+ }
1444
1574
1445
1575
let tcx = fcx.ccx.tcx;
1446
1576
let id = expr.id;
@@ -1911,136 +2041,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1911
2041
}
1912
2042
ast::expr_struct(path, fields, base_expr) => {
1913
2043
// Resolve the path.
1914
- let class_id;
1915
2044
match tcx.def_map.find(id) {
1916
2045
Some(ast::def_class(type_def_id)) => {
1917
- class_id = type_def_id;
2046
+ check_struct_constructor(fcx, id, expr.span, type_def_id,
2047
+ fields, base_expr);
1918
2048
}
1919
2049
_ => {
1920
2050
tcx.sess.span_bug(path.span, ~" structure constructor does \
1921
2051
not name a structure type ");
1922
2052
}
1923
2053
}
1924
-
1925
- // Look up the number of type parameters and the raw type, and
1926
- // determine whether the class is region-parameterized.
1927
- let type_parameter_count, region_parameterized, raw_type;
1928
- if class_id.crate == ast::local_crate {
1929
- region_parameterized =
1930
- tcx.region_paramd_items.find(class_id.node);
1931
- match tcx.items.find(class_id.node) {
1932
- Some(ast_map::node_item(@{
1933
- node: ast::item_class(_, type_parameters),
1934
- _
1935
- }, _)) => {
1936
-
1937
- type_parameter_count = type_parameters.len();
1938
-
1939
- let self_region =
1940
- bound_self_region(region_parameterized);
1941
-
1942
- raw_type = ty::mk_class(tcx, class_id, {
1943
- self_r: self_region,
1944
- self_ty: None,
1945
- tps: ty::ty_params_to_tys(tcx, type_parameters)
1946
- });
1947
- }
1948
- _ => {
1949
- tcx.sess.span_bug(expr.span,
1950
- ~" resolve didn' t map this to a class");
1951
- }
1952
- }
1953
- } else {
1954
- let item_type = ty::lookup_item_type(tcx, class_id);
1955
- type_parameter_count = (*item_type.bounds).len();
1956
- region_parameterized = item_type.region_param;
1957
- raw_type = item_type.ty;
1958
- }
1959
-
1960
- // Generate the struct type.
1961
- let self_region =
1962
- fcx.region_var_if_parameterized(region_parameterized,
1963
- expr.span,
1964
- ty::re_scope(expr.id));
1965
- let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
1966
- let substitutions = {
1967
- self_r: self_region,
1968
- self_ty: None,
1969
- tps: type_parameters
1970
- };
1971
-
1972
- let struct_type = ty::subst(tcx, &substitutions, raw_type);
1973
-
1974
- // Look up the class fields and build up a map.
1975
- let class_fields = ty::lookup_class_fields(tcx, class_id);
1976
- let class_field_map = HashMap();
1977
- let mut fields_found = 0;
1978
- for class_fields.each |field| {
1979
- // XXX: Check visibility here.
1980
- class_field_map.insert(field.ident, (field.id, false));
1981
- }
1982
-
1983
- // Typecheck each field.
1984
- for fields.each |field| {
1985
- match class_field_map.find(field.node.ident) {
1986
- None => {
1987
- tcx.sess.span_err(
1988
- field.span,
1989
- fmt!(" structure has no field named field named `%s`",
1990
- tcx. sess. str_of( field. node. ident) ) ) ;
1991
- }
1992
- Some ( ( _, true ) ) => {
1993
- tcx. sess. span_err(
1994
- field. span,
1995
- fmt!( "field `%s` specified more than once" ,
1996
- tcx. sess. str_of( field. node. ident) ) ) ;
1997
- }
1998
- Some ( ( field_id, false ) ) => {
1999
- let expected_field_type =
2000
- ty:: lookup_field_type( tcx, class_id, field_id,
2001
- & substitutions) ;
2002
- bot |= check_expr( fcx,
2003
- field. node. expr,
2004
- Some ( expected_field_type) ) ;
2005
- fields_found += 1 ;
2006
- }
2007
- }
2008
- }
2009
-
2010
- match base_expr {
2011
- None => {
2012
- // Make sure the programmer specified all the fields.
2013
- assert fields_found <= class_fields. len( ) ;
2014
- if fields_found < class_fields. len( ) {
2015
- let mut missing_fields = ~[ ] ;
2016
- for class_fields. each |class_field| {
2017
- let name = class_field. ident;
2018
- let ( _, seen) = class_field_map. get( name) ;
2019
- if !seen {
2020
- missing_fields. push(
2021
- ~"`" + tcx. sess. str_of( name) + ~"`") ;
2022
- }
2023
- }
2024
-
2025
- tcx. sess. span_err( expr. span,
2026
- fmt!( "missing field%s: %s" ,
2027
- if missing_fields. len( ) == 1 {
2028
- ~""
2029
- } else {
2030
- ~"s"
2031
- },
2032
- str::connect(missing_fields,
2033
- ~" , ")));
2034
- }
2035
- }
2036
- Some(base_expr) => {
2037
- // Just check the base expression.
2038
- check_expr(fcx, base_expr, Some(struct_type));
2039
- }
2040
- }
2041
-
2042
- // Write in the resulting type.
2043
- fcx.write_ty(id, struct_type);
2044
2054
}
2045
2055
ast::expr_field(base, field, tys) => {
2046
2056
bot = check_field(fcx, expr, false, base, field, tys);
0 commit comments