Skip to content

Commit 6c00e54

Browse files
Guide inference along during type_changing_struct_update
1 parent fa68e73 commit 6c00e54

File tree

2 files changed

+56
-3
lines changed
  • compiler/rustc_typeck/src/check
  • src/test/ui/rfcs/rfc-2528-type-changing-struct-update

2 files changed

+56
-3
lines changed

compiler/rustc_typeck/src/check/expr.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -1557,9 +1557,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15571557
// FIXME: We are currently creating two branches here in order to maintain
15581558
// consistency. But they should be merged as much as possible.
15591559
let fru_tys = if self.tcx.features().type_changing_struct_update {
1560-
let base_ty = self.check_expr(base_expr);
15611560
match adt_ty.kind() {
15621561
ty::Adt(adt, substs) if adt.is_struct() => {
1562+
// Make an ADT with fresh inference substitutions. This
1563+
// will allow us to guide inference along so that, e.g.
1564+
// ```
1565+
// let x = MyStruct<'a, B, const C: usize> {
1566+
// f: 1,
1567+
// ..Default::default()
1568+
// };
1569+
// ```
1570+
// will have the default base expression constrained to
1571+
// `MyStruct<'_, _, _>`, as opposed to just `_`... This
1572+
// will allow us to then do a subtyping relation on all
1573+
// of the `remaining_fields` below, per the RFC.
1574+
let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did());
1575+
let base_ty = self.check_expr_has_type_or_error(
1576+
base_expr,
1577+
self.tcx.mk_adt(*adt, fresh_substs),
1578+
|_| {},
1579+
);
1580+
let base_ty = self.shallow_resolve(base_ty);
15631581
match base_ty.kind() {
15641582
ty::Adt(base_adt, base_subs) if adt == base_adt => {
15651583
variant
@@ -1585,7 +1603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15851603
self.register_predicates(obligations)
15861604
}
15871605
// FIXME: Need better diagnostics for `FieldMisMatch` error
1588-
Err(_) => {
1606+
Err(type_error) => {
1607+
debug!("check_expr_struct_fields: {fru_ty} sub {target_ty} failed: {type_error:?}");
15891608
self.report_mismatched_types(
15901609
&cause,
15911610
target_ty,
@@ -1596,7 +1615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15961615
}
15971616
}
15981617
}
1599-
fru_ty
1618+
self.resolve_vars_if_possible(fru_ty)
16001619
})
16011620
.collect()
16021621
}
@@ -1613,6 +1632,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16131632
}
16141633
}
16151634
_ => {
1635+
// Check the base_expr, regardless of a bad expected adt_ty, so we can get
1636+
// type errors on that expression, too.
1637+
self.check_expr(base_expr);
16161638
self.tcx
16171639
.sess
16181640
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// check-pass
2+
3+
#![feature(type_changing_struct_update)]
4+
#![allow(incomplete_features)]
5+
6+
use std::borrow::Cow;
7+
use std::marker::PhantomData;
8+
9+
#[derive(Default)]
10+
struct NonGeneric {
11+
field1: usize,
12+
}
13+
14+
#[derive(Default)]
15+
struct Generic<T, U> {
16+
field1: T,
17+
field2: U,
18+
}
19+
20+
#[derive(Default)]
21+
struct MoreGeneric<'a, const N: usize> {
22+
// If only `for<const N: usize> [u32; N]: Default`...
23+
field1: PhantomData<[u32; N]>,
24+
field2: Cow<'a, str>,
25+
}
26+
27+
fn main() {
28+
let default1 = NonGeneric { ..Default::default() };
29+
let default2: Generic<i32, f32> = Generic { ..Default::default() };
30+
let default3: MoreGeneric<'static, 12> = MoreGeneric { ..Default::default() };
31+
}

0 commit comments

Comments
 (0)