Guide inference along during type_changing_struct_update
This commit is contained in:
parent
fa68e73e99
commit
6c00e54667
@ -1557,9 +1557,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// FIXME: We are currently creating two branches here in order to maintain
|
||||
// consistency. But they should be merged as much as possible.
|
||||
let fru_tys = if self.tcx.features().type_changing_struct_update {
|
||||
let base_ty = self.check_expr(base_expr);
|
||||
match adt_ty.kind() {
|
||||
ty::Adt(adt, substs) if adt.is_struct() => {
|
||||
// Make an ADT with fresh inference substitutions. This
|
||||
// will allow us to guide inference along so that, e.g.
|
||||
// ```
|
||||
// let x = MyStruct<'a, B, const C: usize> {
|
||||
// f: 1,
|
||||
// ..Default::default()
|
||||
// };
|
||||
// ```
|
||||
// will have the default base expression constrained to
|
||||
// `MyStruct<'_, _, _>`, as opposed to just `_`... This
|
||||
// will allow us to then do a subtyping relation on all
|
||||
// of the `remaining_fields` below, per the RFC.
|
||||
let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did());
|
||||
let base_ty = self.check_expr_has_type_or_error(
|
||||
base_expr,
|
||||
self.tcx.mk_adt(*adt, fresh_substs),
|
||||
|_| {},
|
||||
);
|
||||
let base_ty = self.shallow_resolve(base_ty);
|
||||
match base_ty.kind() {
|
||||
ty::Adt(base_adt, base_subs) if adt == base_adt => {
|
||||
variant
|
||||
@ -1585,7 +1603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.register_predicates(obligations)
|
||||
}
|
||||
// FIXME: Need better diagnostics for `FieldMisMatch` error
|
||||
Err(_) => {
|
||||
Err(type_error) => {
|
||||
debug!("check_expr_struct_fields: {fru_ty} sub {target_ty} failed: {type_error:?}");
|
||||
self.report_mismatched_types(
|
||||
&cause,
|
||||
target_ty,
|
||||
@ -1596,7 +1615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
fru_ty
|
||||
self.resolve_vars_if_possible(fru_ty)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -1613,6 +1632,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Check the base_expr, regardless of a bad expected adt_ty, so we can get
|
||||
// type errors on that expression, too.
|
||||
self.check_expr(base_expr);
|
||||
self.tcx
|
||||
.sess
|
||||
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
|
||||
|
@ -0,0 +1,31 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(type_changing_struct_update)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Default)]
|
||||
struct NonGeneric {
|
||||
field1: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Generic<T, U> {
|
||||
field1: T,
|
||||
field2: U,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MoreGeneric<'a, const N: usize> {
|
||||
// If only `for<const N: usize> [u32; N]: Default`...
|
||||
field1: PhantomData<[u32; N]>,
|
||||
field2: Cow<'a, str>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let default1 = NonGeneric { ..Default::default() };
|
||||
let default2: Generic<i32, f32> = Generic { ..Default::default() };
|
||||
let default3: MoreGeneric<'static, 12> = MoreGeneric { ..Default::default() };
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user