Skip to content

Commit

Permalink
don't eagerly normalize SelfCtor type
Browse files Browse the repository at this point in the history
Delay until user annotations are registered.
See the added test.
  • Loading branch information
aliemjay committed Jan 7, 2023
1 parent 030d60f commit bf228ac
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 36 deletions.
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4134,7 +4134,6 @@ dependencies = [
name = "rustc_hir_typeck"
version = "0.1.0"
dependencies = [
"either",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir_typeck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
28 changes: 20 additions & 8 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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?");
Expand Down
34 changes: 8 additions & 26 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/nll/user-annotations/normalization-default.rs
Original file line number Diff line number Diff line change
@@ -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() {}
36 changes: 36 additions & 0 deletions src/test/ui/nll/user-annotations/normalization-default.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 26 additions & 0 deletions src/test/ui/nll/user-annotations/normalization-self.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 36 additions & 0 deletions src/test/ui/nll/user-annotations/normalization-self.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit bf228ac

Please sign in to comment.