don't eagerly normalize SelfCtor type
Delay until user annotations are registered. See the added test.
This commit is contained in:
parent
030d60f1c7
commit
bf228ace5c
8 changed files with 148 additions and 36 deletions
|
|
@ -4134,7 +4134,6 @@ dependencies = [
|
|||
name = "rustc_hir_typeck"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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?");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
22
src/test/ui/nll/user-annotations/normalization-default.rs
Normal file
22
src/test/ui/nll/user-annotations/normalization-default.rs
Normal 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() {}
|
||||
|
|
@ -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
|
||||
|
||||
26
src/test/ui/nll/user-annotations/normalization-self.rs
Normal file
26
src/test/ui/nll/user-annotations/normalization-self.rs
Normal 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() {}
|
||||
36
src/test/ui/nll/user-annotations/normalization-self.stderr
Normal file
36
src/test/ui/nll/user-annotations/normalization-self.stderr
Normal 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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue