Skip to content

Commit 926892d

Browse files
committed
Add feature trigger and enable is_struct check
1 parent 1ab2616 commit 926892d

File tree

3 files changed

+96
-104
lines changed

3 files changed

+96
-104
lines changed

compiler/rustc_typeck/src/check/expr.rs

+85-103
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
3636
use rustc_infer::infer::InferOk;
3737
use rustc_middle::ty;
3838
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
39-
use rustc_middle::ty::error::TypeError::FieldMisMatch;
39+
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
40+
use rustc_middle::ty::relate::expected_found_bool;
4041
use rustc_middle::ty::subst::SubstsRef;
4142
use rustc_middle::ty::Ty;
4243
use rustc_middle::ty::TypeFoldable;
@@ -1375,124 +1376,105 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13751376
}
13761377

13771378
if let Some(base_expr) = base_expr {
1378-
let expected = if self.tcx.features().type_changing_struct_update {
1379-
NoExpectation
1380-
} else {
1381-
ExpectHasType(adt_ty)
1382-
};
1383-
let mut ty = self.check_expr_with_expectation(base_expr, expected);
1384-
1385-
let expected_ty = expected.to_option(&self).unwrap_or(adt_ty);
1386-
// While we don't allow *arbitrary* coercions here, we *do* allow
1387-
// coercions from ! to `expected`.
1388-
if ty.is_never() {
1389-
assert!(
1390-
!self.typeck_results.borrow().adjustments().contains_key(base_expr.hir_id),
1391-
"expression with never type wound up being adjusted"
1392-
);
1393-
let adj_ty = self.next_ty_var(TypeVariableOrigin {
1394-
kind: TypeVariableOriginKind::AdjustmentType,
1395-
span: base_expr.span,
1396-
});
1397-
self.apply_adjustments(
1398-
base_expr,
1399-
vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }],
1400-
);
1401-
ty = adj_ty;
1402-
}
1403-
let cause = self.misc(base_expr.span);
1404-
let mut fru_tys = None;
1405-
let mut err = None;
1406-
let is_struct;
1407-
1408-
if let ty::Adt(adt, substs) = expected_ty.kind() {
1409-
match ty.kind() {
1410-
ty::Adt(base_adt, base_subs) if adt == base_adt => {
1411-
if self.tcx.features().type_changing_struct_update {
1412-
let tys = variant
1413-
.fields
1414-
.iter()
1415-
.map(|f| {
1416-
let fru_ty = self.normalize_associated_types_in(
1417-
expr_span,
1418-
self.field_ty(base_expr.span, f, base_subs),
1419-
);
1420-
let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
1421-
if let Some(_) = remaining_fields.remove(&ident) {
1422-
let target_ty = self.field_ty(base_expr.span, f, substs);
1423-
match self.at(&cause, self.param_env).sup(target_ty, fru_ty)
1424-
{
1425-
Ok(InferOk { obligations, value: () }) => {
1426-
self.register_predicates(obligations)
1427-
}
1428-
// FIXME: Need better diagnostics for `FieldMisMatch` error
1429-
Err(_) => {
1430-
if err.is_none() {
1431-
err = Some(self.report_mismatched_types(
1379+
// FIXME: We are currently creating two branches here in order to maintain
1380+
// consistency. But they should be merged as much as possible.
1381+
let fru_tys = if self.tcx.features().type_changing_struct_update {
1382+
let base_ty = self.check_expr(base_expr);
1383+
match adt_ty.kind() {
1384+
ty::Adt(adt, substs) if adt.is_struct() => {
1385+
match base_ty.kind() {
1386+
ty::Adt(base_adt, base_subs) if adt == base_adt => {
1387+
variant
1388+
.fields
1389+
.iter()
1390+
.map(|f| {
1391+
let fru_ty = self.normalize_associated_types_in(
1392+
expr_span,
1393+
self.field_ty(base_expr.span, f, base_subs),
1394+
);
1395+
let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
1396+
if let Some(_) = remaining_fields.remove(&ident) {
1397+
let target_ty =
1398+
self.field_ty(base_expr.span, f, substs);
1399+
let cause = self.misc(base_expr.span);
1400+
match self
1401+
.at(&cause, self.param_env)
1402+
.sup(target_ty, fru_ty)
1403+
{
1404+
Ok(InferOk { obligations, value: () }) => {
1405+
self.register_predicates(obligations)
1406+
}
1407+
// FIXME: Need better diagnostics for `FieldMisMatch` error
1408+
Err(_) => self
1409+
.report_mismatched_types(
14321410
&cause,
14331411
target_ty,
14341412
fru_ty,
14351413
FieldMisMatch(
14361414
variant.ident.name,
14371415
ident.name,
14381416
),
1439-
))
1440-
}
1417+
)
1418+
.emit(),
14411419
}
14421420
}
1443-
}
1444-
fru_ty
1445-
})
1446-
.collect();
1447-
fru_tys = Some(tys);
1448-
} else {
1449-
err = self.demand_suptype_diag(base_expr.span, expected_ty, ty);
1450-
if err.is_some() && self.tcx.sess.is_nightly_build() {
1451-
feature_err(
1452-
&self.tcx.sess.parse_sess,
1453-
sym::type_changing_struct_update,
1454-
base_expr.span,
1455-
"type changing struct updating is experimental",
1456-
)
1457-
.emit();
1421+
fru_ty
1422+
})
1423+
.collect()
1424+
}
1425+
_ => {
1426+
return self
1427+
.report_mismatched_types(
1428+
&self.misc(base_expr.span),
1429+
adt_ty,
1430+
base_ty,
1431+
Sorts(expected_found_bool(true, adt_ty, base_ty)),
1432+
)
1433+
.emit();
14581434
}
14591435
}
14601436
}
14611437
_ => {
1462-
err = self.demand_suptype_diag(base_expr.span, expected_ty, ty);
1438+
return self
1439+
.tcx
1440+
.sess
1441+
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
14631442
}
14641443
}
1465-
is_struct = adt.is_struct();
1466-
if is_struct && fru_tys.is_none() {
1467-
fru_tys = Some(
1468-
variant
1469-
.fields
1470-
.iter()
1471-
.map(|f| {
1472-
self.normalize_associated_types_in(
1473-
expr_span,
1474-
f.ty(self.tcx, substs),
1475-
)
1476-
})
1477-
.collect(),
1478-
)
1479-
}
14801444
} else {
1481-
err = self.demand_suptype_diag(base_expr.span, expected_ty, ty);
1482-
is_struct = false;
1483-
}
1484-
if let Some(mut err) = err {
1485-
let expr = base_expr.peel_drop_temps();
1486-
self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
1487-
err.emit();
1488-
}
1489-
if let Some(fru_tys) = fru_tys {
1490-
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
1491-
}
1492-
if !is_struct {
1493-
let e = FunctionalRecordUpdateOnNonStruct { span: base_expr.span };
1494-
self.tcx.sess.emit_err(e);
1495-
}
1445+
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
1446+
let base_ty = self.check_expr(base_expr);
1447+
let same_adt = match (adt_ty.kind(), base_ty.kind()) {
1448+
(ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
1449+
_ => false,
1450+
};
1451+
if self.tcx.sess.is_nightly_build() && same_adt {
1452+
feature_err(
1453+
&self.tcx.sess.parse_sess,
1454+
sym::type_changing_struct_update,
1455+
base_expr.span,
1456+
"type changing struct updating is experimental",
1457+
)
1458+
.emit();
1459+
}
1460+
});
1461+
match adt_ty.kind() {
1462+
ty::Adt(adt, substs) if adt.is_struct() => variant
1463+
.fields
1464+
.iter()
1465+
.map(|f| {
1466+
self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
1467+
})
1468+
.collect(),
1469+
_ => {
1470+
return self
1471+
.tcx
1472+
.sess
1473+
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
1474+
}
1475+
}
1476+
};
1477+
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
14961478
} else if kind_name != "union" && !remaining_fields.is_empty() {
14971479
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
14981480
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)

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

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ fn fail_update() {
5050
let m3 = Machine::<i32, i32> {
5151
..m1
5252
//~^ ERROR mismatched types [E0308]
53+
//~| ERROR mismatched types [E0308]
5354
};
5455
}
5556

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ LL | ..m1
1616
= note: expected type `i32`
1717
found type `f64`
1818

19-
error: aborting due to 2 previous errors
19+
error[E0308]: mismatched types
20+
--> $DIR/type-generic-update.rs:51:11
21+
|
22+
LL | ..m1
23+
| ^^ field type mismatch: Machine.message
24+
|
25+
= note: expected type `i32`
26+
found type `f64`
27+
28+
error: aborting due to 3 previous errors
2029

2130
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)