about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-02-28 17:17:25 +0100
committerGitHub <noreply@github.com>2020-02-28 17:17:25 +0100
commit76fe44928281ae6f1ffe881712e02fb2358a4883 (patch)
treef3f229177d5a6e3cd1c0d31de5da10aa420853fb
parentbbf6eec2816d8ce34d2ae51b40e4bb9425b8f65e (diff)
parent6672a047188c1590f13ec9b6dd1b00b35d2bd9c9 (diff)
downloadrust-76fe44928281ae6f1ffe881712e02fb2358a4883.tar.gz
rust-76fe44928281ae6f1ffe881712e02fb2358a4883.zip
Rollup merge of #69340 - Centril:self-ctor-normalize, r=nikomatsakis
instantiate_value_path: on `SelfCtor`, avoid unconstrained tyvars

Fixes https://github.com/rust-lang/rust/issues/69306.

On `Self(...)` (that is, a `Res::SelfCtor`), do not use `self.impl_self_ty(...)`. The problem with that method is that it creates unconstrained inference variables for type parameters in the `impl` (e.g. `impl<T> S0<T>`). These variables then eventually get substituted for something else when they come in contact with the expected type (e.g. `S0<u8>`) or merely the arguments passed to the tuple constructor (e.g. the `0` in `Self(0)`).

Instead of using `self.impl_self_ty(...)`, we instead merely use `let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));` to get the rewritten `res`.

r? @eddyb
-rw-r--r--src/librustc_typeck/check/mod.rs6
-rw-r--r--src/test/ui/issues/issue-69306.rs45
-rw-r--r--src/test/ui/issues/issue-69306.stderr115
3 files changed, 162 insertions, 4 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3c71e8bf6b8..057d5510551 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5447,9 +5447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .unwrap_or(false);
 
         let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.impl_self_ty(span, impl_def_id).ty;
-            let adt_def = ty.ty_adt_def();
-
+            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
             match ty.kind {
                 ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
                     let variant = adt_def.non_enum_variant();
@@ -5464,7 +5462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span,
                         "the `Self` constructor can only be used with tuple or unit structs",
                     );
-                    if let Some(adt_def) = adt_def {
+                    if let Some(adt_def) = ty.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/src/test/ui/issues/issue-69306.rs b/src/test/ui/issues/issue-69306.rs
new file mode 100644
index 00000000000..85d60952ac8
--- /dev/null
+++ b/src/test/ui/issues/issue-69306.rs
@@ -0,0 +1,45 @@
+fn main() {}
+
+struct S0<T>(T);
+impl<T> S0<T> {
+    const C: S0<u8> = Self(0);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+
+    fn foo() {
+        Self(0);
+        //~^ ERROR mismatched types
+    }
+}
+
+// Testing normalization.
+trait Fun {
+    type Out;
+}
+impl<T> Fun for S0<T> {
+    type Out = Self;
+}
+trait Foo<T> {
+    fn foo();
+}
+impl<T> Foo<T> for <S0<T> as Fun>::Out {
+    fn foo() {
+        Self(0); //~ ERROR mismatched types
+    }
+}
+
+struct S1<T, U>(T, U);
+impl<T> S1<T, u8> {
+    const C: S1<u8, u8> = Self(0, 1);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+struct S2<T>(T);
+impl<T> S2<T> {
+    fn map<U>(x: U) -> S2<U> {
+        Self(x)
+        //~^ ERROR mismatched types
+        //~| ERROR mismatched types
+    }
+}
diff --git a/src/test/ui/issues/issue-69306.stderr b/src/test/ui/issues/issue-69306.stderr
new file mode 100644
index 00000000000..a2a42739ca8
--- /dev/null
+++ b/src/test/ui/issues/issue-69306.stderr
@@ -0,0 +1,115 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:5:28
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+LL |     const C: S0<u8> = Self(0);
+   |                            ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:5:23
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+LL |     const C: S0<u8> = Self(0);
+   |                       ^^^^^^^ expected `u8`, found type parameter `T`
+   |
+   = note: expected struct `S0<u8>`
+              found struct `S0<T>`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:10:14
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+...
+LL |         Self(0);
+   |              ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:27:14
+   |
+LL | impl<T> Foo<T> for <S0<T> as Fun>::Out {
+   |      - this type parameter
+LL |     fn foo() {
+LL |         Self(0);
+   |              ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:33:32
+   |
+LL | impl<T> S1<T, u8> {
+   |      - this type parameter
+LL |     const C: S1<u8, u8> = Self(0, 1);
+   |                                ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:33:27
+   |
+LL | impl<T> S1<T, u8> {
+   |      - this type parameter
+LL |     const C: S1<u8, u8> = Self(0, 1);
+   |                           ^^^^^^^^^^ expected `u8`, found type parameter `T`
+   |
+   = note: expected struct `S1<u8, _>`
+              found struct `S1<T, _>`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:41:14
+   |
+LL | impl<T> S2<T> {
+   |      - expected type parameter
+LL |     fn map<U>(x: U) -> S2<U> {
+   |            - found type parameter
+LL |         Self(x)
+   |              ^ expected type parameter `T`, found type parameter `U`
+   |
+   = note: expected type parameter `T`
+              found type parameter `U`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:41:9
+   |
+LL | impl<T> S2<T> {
+   |      - found type parameter
+LL |     fn map<U>(x: U) -> S2<U> {
+   |            -           ----- expected `S2<U>` because of return type
+   |            |
+   |            expected type parameter
+LL |         Self(x)
+   |         ^^^^^^^ expected type parameter `U`, found type parameter `T`
+   |
+   = note: expected struct `S2<U>`
+              found struct `S2<T>`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.