don't eagerly normalize SelfCtor type

Delay until user annotations are registered.
See the added test.
This commit is contained in:
Ali MJ Al-Nasrawy 2022-12-26 01:03:24 +03:00
parent 030d60f1c7
commit bf228ace5c
8 changed files with 148 additions and 36 deletions

View file

@ -4134,7 +4134,6 @@ dependencies = [
name = "rustc_hir_typeck"
version = "0.1.0"
dependencies = [
"either",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
either = "1.5.0"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }

View file

@ -392,6 +392,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty.normalized
}
pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> {
match (ty.raw.kind(), ty.normalized.kind()) {
(ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None },
(_, ty::Adt(adt, substs)) => UserSubsts {
substs,
user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }),
},
_ => bug!("non-adt type {:?}", ty),
}
}
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
@ -1082,20 +1093,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.unwrap_or(false);
let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
let ty = tcx.at(span).type_of(impl_def_id);
let ty = self.normalize(span, ty);
match *ty.kind() {
ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
let variant = adt_def.non_enum_variant();
let (ctor_kind, ctor_def_id) = variant.ctor.unwrap();
(Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs))
let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id));
match ty.normalized.ty_adt_def() {
Some(adt_def) if adt_def.has_ctor() => {
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let user_substs = Self::user_substs_for_adt(ty);
user_self_ty = user_substs.user_self_ty;
(new_res, Some(user_substs.substs))
}
_ => {
let mut err = tcx.sess.struct_span_err(
span,
"the `Self` constructor can only be used with tuple or unit structs",
);
if let Some(adt_def) = ty.ty_adt_def() {
if let Some(adt_def) = ty.normalized.ty_adt_def() {
match adt_def.adt_kind() {
AdtKind::Enum => {
err.help("did you mean to use one of the enum's variants?");

View file

@ -32,8 +32,6 @@ use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, sym, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use either::Either;
use std::iter;
use std::mem;
use std::ops::ControlFlow;
@ -1233,44 +1231,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
return None;
}
Res::Def(DefKind::Variant, _) => match (ty.raw.kind(), ty.normalized.kind()) {
(ty::Adt(adt, substs), _) => {
Some((adt.variant_of_res(def), adt.did(), substs, Either::Left(substs)))
}
(_, ty::Adt(adt, substs)) => {
Some((adt.variant_of_res(def), adt.did(), substs, Either::Right(ty.raw)))
Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
Some(adt) => {
Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty)))
}
_ => bug!("unexpected type: {:?}", ty.normalized),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => match (ty.raw.kind(), ty.normalized.kind()) {
(ty::Adt(adt, substs), _) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did(), substs, Either::Left(substs)))
}
(_, ty::Adt(adt, substs)) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did(), substs, Either::Right(ty.raw)))
| Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
Some(adt) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty)))
}
_ => None,
},
_ => bug!("unexpected definition: {:?}", def),
};
if let Some((variant, did, substs, user_annotation)) = variant {
if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant {
debug!("check_struct_path: did={:?} substs={:?}", did, substs);
// Register type annotation.
self.probe(|_| {
// UserSubsts and UserSelfTy are mutually exclusive here.
let (user_substs, self_ty) = match user_annotation {
Either::Left(substs) => (*substs, None),
Either::Right(self_ty) => {
(self.fresh_substs_for_item(path_span, did), Some(self_ty))
}
};
let self_ty = self_ty.map(|self_ty| ty::UserSelfTy { impl_def_id: did, self_ty });
self.write_user_type_annotation_from_substs(hir_id, did, user_substs, self_ty);
});
self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty);
// Check bounds on type arguments used in the path.
self.add_required_obligations_for_hir(path_span, did, substs, hir_id);

View file

@ -0,0 +1,22 @@
// check-fail
trait Trait { type Assoc; }
impl<'a> Trait for &'a () { type Assoc = &'a (); }
struct MyTuple<T, U = <&'static () as Trait>::Assoc>(T, U);
fn test_tuple(x: &(), y: &()) {
MyTuple::<_>((), x);
//~^ ERROR
let _: MyTuple::<_> = MyTuple((), y);
//~^ ERROR
}
struct MyStruct<T, U = <&'static () as Trait>::Assoc> { val: (T, U), }
fn test_struct(x: &(), y: &()) {
MyStruct::<_> { val: ((), x) };
//~^ ERROR
let _: MyStruct::<_> = MyStruct { val: ((), y) };
//~^ ERROR
}
fn main() {}

View file

@ -0,0 +1,36 @@
error: lifetime may not live long enough
--> $DIR/normalization-default.rs:8:22
|
LL | fn test_tuple(x: &(), y: &()) {
| - let's call the lifetime of this reference `'1`
LL | MyTuple::<_>((), x);
| ^ this usage requires that `'1` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-default.rs:10:12
|
LL | fn test_tuple(x: &(), y: &()) {
| - let's call the lifetime of this reference `'2`
...
LL | let _: MyTuple::<_> = MyTuple((), y);
| ^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-default.rs:16:26
|
LL | fn test_struct(x: &(), y: &()) {
| - let's call the lifetime of this reference `'1`
LL | MyStruct::<_> { val: ((), x) };
| ^^^^^^^ this usage requires that `'1` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-default.rs:18:12
|
LL | fn test_struct(x: &(), y: &()) {
| - let's call the lifetime of this reference `'2`
...
LL | let _: MyStruct::<_> = MyStruct { val: ((), y) };
| ^^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
error: aborting due to 4 previous errors

View file

@ -0,0 +1,26 @@
// check-fail
trait Trait { type Assoc; }
impl<'a> Trait for &'a () { type Assoc = &'a (); }
struct MyTuple<T>(T);
impl MyTuple<<&'static () as Trait>::Assoc> {
fn test(x: &(), y: &()) {
Self(x);
//~^ ERROR
let _: Self = MyTuple(y);
//~^ ERROR
}
}
struct MyStruct<T> { val: T, }
impl MyStruct<<&'static () as Trait>::Assoc> {
fn test(x: &(), y: &()) {
Self { val: x };
//~^ ERROR
let _: Self = MyStruct { val: y };
//~^ ERROR
}
}
fn main() {}

View file

@ -0,0 +1,36 @@
error: lifetime may not live long enough
--> $DIR/normalization-self.rs:9:14
|
LL | fn test(x: &(), y: &()) {
| - let's call the lifetime of this reference `'1`
LL | Self(x);
| ^ this usage requires that `'1` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-self.rs:11:16
|
LL | fn test(x: &(), y: &()) {
| - let's call the lifetime of this reference `'2`
...
LL | let _: Self = MyTuple(y);
| ^^^^ type annotation requires that `'2` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-self.rs:19:21
|
LL | fn test(x: &(), y: &()) {
| - let's call the lifetime of this reference `'1`
LL | Self { val: x };
| ^ this usage requires that `'1` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/normalization-self.rs:21:16
|
LL | fn test(x: &(), y: &()) {
| - let's call the lifetime of this reference `'2`
...
LL | let _: Self = MyStruct { val: y };
| ^^^^ type annotation requires that `'2` must outlive `'static`
error: aborting due to 4 previous errors