about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-06-03 15:04:40 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2019-06-03 15:04:40 +0100
commit794239d9a4f9ce0e1a0fb26ee737c80044b76587 (patch)
tree5b8a04c38002ab107dbcca566f1e2b216f74350a
parent2751b867a7fa0b14dbe5ca5f315e8f373bf8a5f3 (diff)
downloadrust-794239d9a4f9ce0e1a0fb26ee737c80044b76587.tar.gz
rust-794239d9a4f9ce0e1a0fb26ee737c80044b76587.zip
Don't canonicalize `'static` in normalize
-rw-r--r--src/librustc/infer/canonical/canonicalizer.rs10
-rw-r--r--src/librustc/traits/query/normalize.rs4
-rw-r--r--src/test/ui/nll/issue-61311-normalize.rs34
-rw-r--r--src/test/ui/nll/issue-61320-normalize.rs160
4 files changed, 204 insertions, 4 deletions
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index 0e9dbcac5cd..ae4bfcaa903 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -115,13 +115,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 
     /// A hacky variant of `canonicalize_query` that does not
     /// canonicalize `'static`. Unfortunately, the existing leak
-    /// check treaks `'static` differently in some cases (see also
+    /// check treats `'static` differently in some cases (see also
     /// #33684), so if we are performing an operation that may need to
     /// prove "leak-check" related things, we leave `'static`
     /// alone.
+    ///
+    /// `'static` is also special cased when winnowing candidates when
+    /// selecting implementation candidates, so we also have to leave `'static`
+    /// alone for queries that do selection.
     //
-    // FIXME(#48536): once we have universes, we can remove this and just use
-    // `canonicalize_query`.
+    // FIXME(#48536): once the above issues are resolved, we can remove this
+    // and just use `canonicalize_query`.
     pub fn canonicalize_hr_query_hack<V>(
         &self,
         value: &V,
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index d09a9c10786..0b20ec884fc 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -145,7 +145,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                 let gcx = self.infcx.tcx.global_tcx();
 
                 let mut orig_values = OriginalQueryValues::default();
-                let c_data = self.infcx.canonicalize_query(
+                // HACK(matthewjasper) `'static` is special-cased in selection,
+                // so we cannot canonicalize it.
+                let c_data = self.infcx.canonicalize_hr_query_hack(
                     &self.param_env.and(*data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
diff --git a/src/test/ui/nll/issue-61311-normalize.rs b/src/test/ui/nll/issue-61311-normalize.rs
new file mode 100644
index 00000000000..1164e9ef2d6
--- /dev/null
+++ b/src/test/ui/nll/issue-61311-normalize.rs
@@ -0,0 +1,34 @@
+// Regression test for #61311
+// We would ICE after failing to normalize `Self::Proj` in the `impl` below.
+
+// compile-pass
+
+pub struct Unit;
+trait Obj {}
+
+trait Bound {}
+impl Bound for Unit {}
+
+pub trait HasProj {
+    type Proj;
+}
+
+impl<T> HasProj for T {
+    type Proj = Unit;
+}
+
+trait HasProjFn {
+    type Proj;
+    fn the_fn(_: Self::Proj);
+}
+
+impl HasProjFn for Unit
+where
+    Box<dyn Obj + 'static>: HasProj,
+    <Box<dyn Obj + 'static> as HasProj>::Proj: Bound,
+{
+    type Proj = Unit;
+    fn the_fn(_: Self::Proj) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-61320-normalize.rs b/src/test/ui/nll/issue-61320-normalize.rs
new file mode 100644
index 00000000000..a36ccd36113
--- /dev/null
+++ b/src/test/ui/nll/issue-61320-normalize.rs
@@ -0,0 +1,160 @@
+// Regression test for #61320
+// This is the same issue as #61311, just a larger test case.
+
+// compile-pass
+
+pub struct AndThen<A, B, F>
+where
+    A: Future,
+    B: IntoFuture,
+{
+    state: (A, B::Future, F),
+}
+
+pub struct FutureResult<T, E> {
+    inner: Option<Result<T, E>>,
+}
+
+impl<T, E> Future for FutureResult<T, E> {
+    type Item = T;
+    type Error = E;
+
+    fn poll(&mut self) -> Poll<T, E> {
+        unimplemented!()
+    }
+}
+
+pub type Poll<T, E> = Result<T, E>;
+
+impl<A, B, F> Future for AndThen<A, B, F>
+where
+    A: Future,
+    B: IntoFuture<Error = A::Error>,
+    F: FnOnce(A::Item) -> B,
+{
+    type Item = B::Item;
+    type Error = B::Error;
+
+    fn poll(&mut self) -> Poll<B::Item, B::Error> {
+        unimplemented!()
+    }
+}
+
+pub trait Future {
+    type Item;
+
+    type Error;
+
+    fn poll(&mut self) -> Poll<Self::Item, Self::Error>;
+
+    fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
+    where
+        F: FnOnce(Self::Item) -> B,
+        B: IntoFuture<Error = Self::Error>,
+        Self: Sized,
+    {
+        unimplemented!()
+    }
+}
+
+pub trait IntoFuture {
+    /// The future that this type can be converted into.
+    type Future: Future<Item = Self::Item, Error = Self::Error>;
+
+    /// The item that the future may resolve with.
+    type Item;
+    /// The error that the future may resolve with.
+    type Error;
+
+    /// Consumes this object and produces a future.
+    fn into_future(self) -> Self::Future;
+}
+
+impl<F: Future> IntoFuture for F {
+    type Future = F;
+    type Item = F::Item;
+    type Error = F::Error;
+
+    fn into_future(self) -> F {
+        self
+    }
+}
+
+impl<F: ?Sized + Future> Future for ::std::boxed::Box<F> {
+    type Item = F::Item;
+    type Error = F::Error;
+
+    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
+        (**self).poll()
+    }
+}
+
+impl<T, E> IntoFuture for Result<T, E> {
+    type Future = FutureResult<T, E>;
+    type Item = T;
+    type Error = E;
+
+    fn into_future(self) -> FutureResult<T, E> {
+        unimplemented!()
+    }
+}
+
+struct Request<T>(T);
+
+trait RequestContext {}
+impl<T> RequestContext for T {}
+struct NoContext;
+impl AsRef<NoContext> for NoContext {
+    fn as_ref(&self) -> &Self {
+        &NoContext
+    }
+}
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+type DefaultFuture<T, E> = Box<dyn Future<Item = T, Error = E> + Send>;
+
+trait Guard: Sized {
+    type Result: IntoFuture<Item = Self, Error = BoxedError>;
+    fn from_request(request: &Request<()>) -> Self::Result;
+}
+
+trait FromRequest: Sized {
+    type Context;
+    type Future: Future<Item = Self, Error = BoxedError> + Send;
+    fn from_request(request: Request<()>) -> Self::Future;
+}
+
+struct MyGuard;
+impl Guard for MyGuard {
+    type Result = Result<Self, BoxedError>;
+    fn from_request(_request: &Request<()>) -> Self::Result {
+        Ok(MyGuard)
+    }
+}
+
+struct Generic<I> {
+    _inner: I,
+}
+
+impl<I> FromRequest for Generic<I>
+where
+    MyGuard: Guard,
+    <MyGuard as Guard>::Result: IntoFuture<Item = MyGuard, Error = BoxedError>,
+    <<MyGuard as Guard>::Result as IntoFuture>::Future: Send,
+    I: FromRequest<Context = NoContext>,
+{
+    type Future = DefaultFuture<Self, BoxedError>;
+    type Context = NoContext;
+    fn from_request(headers: Request<()>) -> DefaultFuture<Self, BoxedError> {
+        let _future = <MyGuard as Guard>::from_request(&headers)
+            .into_future()
+            .and_then(move |_| {
+                <I as FromRequest>::from_request(headers)
+                    .into_future()
+                    .and_then(move |fld_inner| Ok(Generic { _inner: fld_inner }).into_future())
+            });
+        panic!();
+    }
+}
+
+fn main() {}