@@ -814,7 +814,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
814
814
fn check_call ( fcx : @fn_ctxt , sp : span , call_expr_id : ast:: node_id ,
815
815
f : @ast:: expr , args : ~[ @ast:: expr ] ) -> bool {
816
816
817
- let mut bot = check_expr ( fcx, f, none) ;
817
+ // Index expressions need to be handled seperately, to inform
818
+ // them that they appear in call position.
819
+ let mut bot = alt f. node {
820
+ ast:: expr_field ( base, field, tys) {
821
+ check_field ( fcx, f, true , base, field, tys)
822
+ }
823
+ _ { check_expr( fcx, f, none) }
824
+ } ;
818
825
let fn_ty = fcx. expr_ty ( f) ;
819
826
820
827
// Call the generic checker.
@@ -1051,6 +1058,101 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1051
1058
is_loop_body, some ( fcx) ) ;
1052
1059
}
1053
1060
1061
+ // Check field access expressions
1062
+ fn check_field ( fcx : @fn_ctxt , expr : @ast:: expr , is_callee : bool ,
1063
+ base : @ast:: expr , field : ast:: ident , tys : ~[ @ast:: ty ] )
1064
+ -> bool {
1065
+ let tcx = fcx. ccx . tcx ;
1066
+ let bot = check_expr ( fcx, base, none) ;
1067
+ let expr_t = structurally_resolved_type ( fcx, expr. span ,
1068
+ fcx. expr_ty ( base) ) ;
1069
+ let base_t = do_autoderef ( fcx, expr. span , expr_t) ;
1070
+ let mut handled = false ;
1071
+ let n_tys = vec:: len ( tys) ;
1072
+ alt structure_of ( fcx, expr. span , base_t) {
1073
+ ty:: ty_rec ( fields) {
1074
+ alt ty:: field_idx ( field, fields) {
1075
+ some ( ix) {
1076
+ if n_tys > 0 u {
1077
+ tcx. sess . span_err ( expr. span ,
1078
+ "can't provide type parameters \
1079
+ to a field access") ;
1080
+ }
1081
+ fcx. write_ty ( expr. id , fields[ ix] . mt . ty ) ;
1082
+ handled = true ;
1083
+ }
1084
+ _ { }
1085
+ }
1086
+ }
1087
+ ty:: ty_class ( base_id, substs) {
1088
+ // This is just for fields -- the same code handles
1089
+ // methods in both classes and traits
1090
+
1091
+ // (1) verify that the class id actually has a field called
1092
+ // field
1093
+ #debug ( "class named %s" , ty_to_str ( tcx, base_t) ) ;
1094
+ /*
1095
+ check whether this is a self-reference or not, which
1096
+ determines whether we look at all fields or only public
1097
+ ones
1098
+ */
1099
+ let cls_items = if self_ref ( fcx, base. id ) {
1100
+ // base expr is "self" -- consider all fields
1101
+ ty:: lookup_class_fields ( tcx, base_id)
1102
+ }
1103
+ else {
1104
+ lookup_public_fields ( tcx, base_id)
1105
+ } ;
1106
+ alt lookup_field_ty ( tcx, base_id, cls_items, field, substs) {
1107
+ some ( field_ty) {
1108
+ // (2) look up what field's type is, and return it
1109
+ fcx. write_ty ( expr. id , field_ty) ;
1110
+ handled = true ;
1111
+ }
1112
+ none { }
1113
+ }
1114
+ }
1115
+ _ { }
1116
+ }
1117
+ if !handled {
1118
+ let tps = vec:: map ( tys, |ty| fcx. to_ty ( ty) ) ;
1119
+ let is_self_ref = self_ref ( fcx, base. id ) ;
1120
+
1121
+ // this will be the call or block that immediately
1122
+ // encloses the method call
1123
+ let borrow_scope = fcx. tcx ( ) . region_map . get ( expr. id ) ;
1124
+
1125
+ let lkup = method:: lookup ( fcx, expr, base, borrow_scope,
1126
+ expr. id , field, expr_t, tps,
1127
+ is_self_ref) ;
1128
+ alt lkup. method ( ) {
1129
+ some ( entry) {
1130
+ fcx. ccx . method_map . insert ( expr. id , entry) ;
1131
+
1132
+ // If we have resolved to a method but this is not in
1133
+ // a callee position, error
1134
+ if !is_callee {
1135
+ tcx. sess . span_err (
1136
+ expr. span ,
1137
+ "attempted to take value of method \
1138
+ (try writing an anonymous function)") ;
1139
+ }
1140
+ }
1141
+ none {
1142
+ let t_err = fcx. infcx . resolve_type_vars_if_possible ( expr_t) ;
1143
+ let msg = #fmt[ "attempted access of field `%s` on type `%s`, \
1144
+ but no public field or method with that name \
1145
+ was found",
1146
+ * field, fcx. infcx . ty_to_str ( t_err) ] ;
1147
+ tcx. sess . span_err ( expr. span , msg) ;
1148
+ // NB: Adding a bogus type to allow typechecking to continue
1149
+ fcx. write_ty ( expr. id , fcx. infcx . next_ty_var ( ) ) ;
1150
+ }
1151
+ }
1152
+ }
1153
+ ret bot;
1154
+ }
1155
+
1054
1156
1055
1157
let tcx = fcx. ccx . tcx ;
1056
1158
let id = expr. id ;
@@ -1489,84 +1591,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1489
1591
}
1490
1592
}
1491
1593
ast:: expr_field ( base, field, tys) {
1492
- bot |= check_expr ( fcx, base, none) ;
1493
- let expr_t = structurally_resolved_type ( fcx, expr. span ,
1494
- fcx. expr_ty ( base) ) ;
1495
- let base_t = do_autoderef ( fcx, expr. span , expr_t) ;
1496
- let mut handled = false ;
1497
- let n_tys = vec:: len ( tys) ;
1498
- alt structure_of ( fcx, expr. span , base_t) {
1499
- ty:: ty_rec ( fields) {
1500
- alt ty:: field_idx ( field, fields) {
1501
- some ( ix) {
1502
- if n_tys > 0 u {
1503
- tcx. sess . span_err ( expr. span ,
1504
- "can't provide type parameters \
1505
- to a field access") ;
1506
- }
1507
- fcx. write_ty ( id, fields[ ix] . mt . ty ) ;
1508
- handled = true ;
1509
- }
1510
- _ { }
1511
- }
1512
- }
1513
- ty:: ty_class ( base_id, substs) {
1514
- // This is just for fields -- the same code handles
1515
- // methods in both classes and traits
1516
-
1517
- // (1) verify that the class id actually has a field called
1518
- // field
1519
- #debug ( "class named %s" , ty_to_str ( tcx, base_t) ) ;
1520
- /*
1521
- check whether this is a self-reference or not, which
1522
- determines whether we look at all fields or only public
1523
- ones
1524
- */
1525
- let cls_items = if self_ref ( fcx, base. id ) {
1526
- // base expr is "self" -- consider all fields
1527
- ty:: lookup_class_fields ( tcx, base_id)
1528
- }
1529
- else {
1530
- lookup_public_fields ( tcx, base_id)
1531
- } ;
1532
- alt lookup_field_ty ( tcx, base_id, cls_items, field, substs) {
1533
- some ( field_ty) {
1534
- // (2) look up what field's type is, and return it
1535
- fcx. write_ty ( id, field_ty) ;
1536
- handled = true ;
1537
- }
1538
- none { }
1539
- }
1540
- }
1541
- _ { }
1542
- }
1543
- if !handled {
1544
- let tps = vec:: map ( tys, |ty| fcx. to_ty ( ty) ) ;
1545
- let is_self_ref = self_ref ( fcx, base. id ) ;
1546
-
1547
- // this will be the call or block that immediately
1548
- // encloses the method call
1549
- let borrow_scope = fcx. tcx ( ) . region_map . get ( expr. id ) ;
1550
-
1551
- let lkup = method:: lookup ( fcx, expr, base, borrow_scope,
1552
- expr. id , field, expr_t, tps,
1553
- is_self_ref) ;
1554
- alt lkup. method ( ) {
1555
- some ( entry) {
1556
- fcx. ccx . method_map . insert ( id, entry) ;
1557
- }
1558
- none {
1559
- let t_err = fcx. infcx . resolve_type_vars_if_possible ( expr_t) ;
1560
- let msg = #fmt[ "attempted access of field `%s` on type `%s`, \
1561
- but no public field or method with that name \
1562
- was found",
1563
- * field, fcx. infcx . ty_to_str ( t_err) ] ;
1564
- tcx. sess . span_err ( expr. span , msg) ;
1565
- // NB: Adding a bogus type to allow typechecking to continue
1566
- fcx. write_ty ( id, fcx. infcx . next_ty_var ( ) ) ;
1567
- }
1568
- }
1569
- }
1594
+ bot = check_field ( fcx, expr, false , base, field, tys) ;
1570
1595
}
1571
1596
ast:: expr_index ( base, idx) {
1572
1597
bot |= check_expr ( fcx, base, none) ;
0 commit comments