about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2022-12-26 01:03:24 +0300
committerAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-01-07 13:42:16 +0300
commitbf228ace5cf6824078d6d36144ad8a65f07fa8d3 (patch)
tree94b4721d3a1b4ff0150ffb8d2129109916583e87
parent030d60f1c729c01ef9ea11a1adb153c7c58e5fe2 (diff)
downloadrust-bf228ace5cf6824078d6d36144ad8a65f07fa8d3.tar.gz
rust-bf228ace5cf6824078d6d36144ad8a65f07fa8d3.zip
don't eagerly normalize SelfCtor type
Delay until user annotations are registered.
See the added test.
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs34
-rw-r--r--src/test/ui/nll/user-annotations/normalization-default.rs22
-rw-r--r--src/test/ui/nll/user-annotations/normalization-default.stderr36
-rw-r--r--src/test/ui/nll/user-annotations/normalization-self.rs26
-rw-r--r--src/test/ui/nll/user-annotations/normalization-self.stderr36
8 files changed, 148 insertions, 36 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fd55c121bc4..4f48506b5af 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4134,7 +4134,6 @@ dependencies = [
 name = "rustc_hir_typeck"
 version = "0.1.0"
 dependencies = [
- "either",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index 114b2d37fb8..093f9bb8448 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -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" }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 970e84bf054..b7681d108ed 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -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?");
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 22922088895..da411d0642e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -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);
diff --git a/src/test/ui/nll/user-annotations/normalization-default.rs b/src/test/ui/nll/user-annotations/normalization-default.rs
new file mode 100644
index 00000000000..fa52e6d857f
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization-default.rs
@@ -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() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-default.stderr b/src/test/ui/nll/user-annotations/normalization-default.stderr
new file mode 100644
index 00000000000..6c73ac69254
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization-default.stderr
@@ -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
+
diff --git a/src/test/ui/nll/user-annotations/normalization-self.rs b/src/test/ui/nll/user-annotations/normalization-self.rs
new file mode 100644
index 00000000000..c18760b53cf
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization-self.rs
@@ -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() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-self.stderr b/src/test/ui/nll/user-annotations/normalization-self.stderr
new file mode 100644
index 00000000000..e231ed03c2e
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization-self.stderr
@@ -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
+