Skip to content

Commit f3679bc

Browse files
committed
move the processing part of base_expr into check_expr_struct_fields
1 parent 7bde18a commit f3679bc

File tree

3 files changed

+92
-104
lines changed

3 files changed

+92
-104
lines changed

compiler/rustc_typeck/src/check/expr.rs

+90-102
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::type_error_struct;
2323

2424
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
2525
use rustc_ast as ast;
26-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
26+
use rustc_data_structures::fx::FxHashMap;
2727
use rustc_data_structures::stack::ensure_sufficient_stack;
2828
use rustc_errors::ErrorReported;
2929
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
@@ -1264,109 +1264,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12641264
.emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
12651265
}
12661266

1267-
let (error_happened, mut remaining_fields) = self.check_expr_struct_fields(
1267+
self.check_expr_struct_fields(
12681268
adt_ty,
12691269
expected,
12701270
expr.hir_id,
12711271
qpath.span(),
12721272
variant,
12731273
fields,
1274-
base_expr.is_none(),
1274+
base_expr,
12751275
expr.span,
12761276
);
1277-
if let Some(base_expr) = base_expr {
1278-
// If check_expr_struct_fields hit an error, do not attempt to populate
1279-
// the fields with the base_expr. This could cause us to hit errors later
1280-
// when certain fields are assumed to exist that in fact do not.
1281-
if !error_happened {
1282-
// FIXME: We are currently creating two branches here in order to maintain
1283-
// consistency. But they should be merged as much as possible.
1284-
if self.tcx.features().type_changing_struct_update {
1285-
let base_ty = self.check_expr(base_expr);
1286-
match (adt_ty.kind(), base_ty.kind()) {
1287-
(ty::Adt(adt, substs), ty::Adt(base_adt, base_subs)) if adt == base_adt => {
1288-
if !adt.is_struct() {
1289-
self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
1290-
span: base_expr.span,
1291-
});
1292-
};
1293-
let fru_field_types = variant
1294-
.fields
1295-
.iter()
1296-
.map(|f| {
1297-
let fru_ty = self.normalize_associated_types_in(
1298-
expr.span,
1299-
self.field_ty(base_expr.span, f, base_subs),
1300-
);
1301-
let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
1302-
if remaining_fields.remove(&ident) {
1303-
let target_ty = self.field_ty(base_expr.span, f, substs);
1304-
let cause = self.misc(base_expr.span);
1305-
match self.at(&cause, self.param_env).sup(target_ty, fru_ty)
1306-
{
1307-
Ok(InferOk { obligations, value: () }) => {
1308-
self.register_predicates(obligations)
1309-
}
1310-
// FIXME: Needs better diagnostics here
1311-
Err(_) => self
1312-
.report_mismatched_types(
1313-
&cause,
1314-
target_ty,
1315-
fru_ty,
1316-
FieldMisMatch(variant.ident.name, ident.name),
1317-
)
1318-
.emit(),
1319-
}
1320-
}
1321-
fru_ty
1322-
})
1323-
.collect();
1324-
1325-
self.typeck_results
1326-
.borrow_mut()
1327-
.fru_field_types_mut()
1328-
.insert(expr.hir_id, fru_field_types);
1329-
}
1330-
_ => {
1331-
self.report_mismatched_types(
1332-
&self.misc(base_expr.span),
1333-
adt_ty,
1334-
base_ty,
1335-
Mismatch,
1336-
)
1337-
.emit();
1338-
}
1339-
}
1340-
} else {
1341-
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
1342-
match adt_ty.kind() {
1343-
ty::Adt(adt, substs) if adt.is_struct() => {
1344-
let fru_field_types = adt
1345-
.non_enum_variant()
1346-
.fields
1347-
.iter()
1348-
.map(|f| {
1349-
self.normalize_associated_types_in(
1350-
expr.span,
1351-
f.ty(self.tcx, substs),
1352-
)
1353-
})
1354-
.collect();
1355-
1356-
self.typeck_results
1357-
.borrow_mut()
1358-
.fru_field_types_mut()
1359-
.insert(expr.hir_id, fru_field_types);
1360-
}
1361-
_ => {
1362-
self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
1363-
span: base_expr.span,
1364-
});
1365-
}
1366-
}
1367-
};
1368-
}
1369-
}
1277+
13701278
self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
13711279
adt_ty
13721280
}
@@ -1379,9 +1287,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13791287
span: Span,
13801288
variant: &'tcx ty::VariantDef,
13811289
ast_fields: &'tcx [hir::ExprField<'tcx>],
1382-
check_completeness: bool,
1290+
base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
13831291
expr_span: Span,
1384-
) -> (bool, FxHashSet<Ident>) {
1292+
) {
13851293
let tcx = self.tcx;
13861294

13871295
let adt_ty_hint = self
@@ -1456,19 +1364,99 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14561364
)
14571365
.emit();
14581366
}
1459-
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
1367+
}
1368+
1369+
// If check_expr_struct_fields hit an error, do not attempt to populate
1370+
// the fields with the base_expr. This could cause us to hit errors later
1371+
// when certain fields are assumed to exist that in fact do not.
1372+
if error_happened {
1373+
return;
1374+
}
1375+
1376+
if let Some(base_expr) = base_expr {
1377+
// FIXME: We are currently creating two branches here in order to maintain
1378+
// consistency. But they should be merged as much as possible.
1379+
let fru_tys = if self.tcx.features().type_changing_struct_update {
1380+
let base_ty = self.check_expr(base_expr);
1381+
match (adt_ty.kind(), base_ty.kind()) {
1382+
(ty::Adt(adt, substs), ty::Adt(base_adt, base_subs)) if adt == base_adt => {
1383+
if !adt.is_struct() {
1384+
self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
1385+
span: base_expr.span,
1386+
});
1387+
};
1388+
variant
1389+
.fields
1390+
.iter()
1391+
.map(|f| {
1392+
let fru_ty = self.normalize_associated_types_in(
1393+
expr_span,
1394+
self.field_ty(base_expr.span, f, base_subs),
1395+
);
1396+
let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
1397+
if let Some(_) = remaining_fields.remove(&ident) {
1398+
let target_ty = self.field_ty(base_expr.span, f, substs);
1399+
let cause = self.misc(base_expr.span);
1400+
match self.at(&cause, self.param_env).sup(target_ty, fru_ty) {
1401+
Ok(InferOk { obligations, value: () }) => {
1402+
self.register_predicates(obligations)
1403+
}
1404+
// FIXME: Need better diagnostics for `FieldMisMatch` error
1405+
Err(_) => self
1406+
.report_mismatched_types(
1407+
&cause,
1408+
target_ty,
1409+
fru_ty,
1410+
FieldMisMatch(variant.ident.name, ident.name),
1411+
)
1412+
.emit(),
1413+
}
1414+
}
1415+
fru_ty
1416+
})
1417+
.collect()
1418+
}
1419+
_ => {
1420+
return self
1421+
.report_mismatched_types(
1422+
&self.misc(base_expr.span),
1423+
adt_ty,
1424+
base_ty,
1425+
Mismatch,
1426+
)
1427+
.emit();
1428+
}
1429+
}
1430+
} else {
1431+
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
1432+
match adt_ty.kind() {
1433+
ty::Adt(adt, substs) if adt.is_struct() => variant
1434+
.fields
1435+
.iter()
1436+
.map(|f| {
1437+
self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
1438+
})
1439+
.collect(),
1440+
_ => {
1441+
return self
1442+
.tcx
1443+
.sess
1444+
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
1445+
}
1446+
}
1447+
};
1448+
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
1449+
} else if kind_name != "union" && !remaining_fields.is_empty() {
14601450
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
14611451
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
14621452
});
14631453

14641454
if inaccessible_remaining_fields {
14651455
self.report_inaccessible_fields(adt_ty, span);
14661456
} else {
1467-
self.report_missing_fields(adt_ty, span, remaining_fields.clone());
1457+
self.report_missing_fields(adt_ty, span, remaining_fields);
14681458
}
14691459
}
1470-
1471-
(error_happened, remaining_fields.iter().map(|(ident, _)| ident.clone()).collect())
14721460
}
14731461

14741462
fn check_struct_fields_on_error(

src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ fn update_to_state2() {
1717
common_field1: "hello",
1818
common_field2: 2,
1919
};
20+
// FIXME: this should trigger feature gate
2021
let m2: Machine<State2> = Machine {
2122
state: State2,
2223
..m1 //~ ERROR mismatched types
2324
};
24-
// FIXME: this should trigger feature gate
2525
assert_eq!(State2, m2.state);
2626
}
2727

src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/feature-gate.rs:22:11
2+
--> $DIR/feature-gate.rs:23:11
33
|
44
LL | ..m1
55
| ^^ expected struct `State2`, found struct `State1`

0 commit comments

Comments
 (0)