about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-10-23 08:14:32 +0200
committerGitHub <noreply@github.com>2022-10-23 08:14:32 +0200
commit72f75d18b15608cfe6461892f3ed53cdcdf248d8 (patch)
tree88fa6cd940d91186b3ac91c1cbf5d04712d94718
parentff689a1404081871afd31814f31db508bcd560dc (diff)
parentcb61113cdc158de18993a94bc6bb39aee6950a9b (diff)
downloadrust-72f75d18b15608cfe6461892f3ed53cdcdf248d8.tar.gz
rust-72f75d18b15608cfe6461892f3ed53cdcdf248d8.zip
Rollup merge of #103368 - compiler-errors:normalization-ambiguity-bug, r=oli-obk
Delay ambiguity span bug in normalize query iff not rustdoc

Oli and I decided that the compiler debt of adding another usage of `tcx.sess.opts.actually_rustdoc` is fine, because we don't really want to add more complexity to the normalize query, and moving rustdoc to use fulfill normalization (`fully_normalize`, i.e. not use the normalize query) is unnecessary overhead given that it's skipping binders and stuff.

r? oli-obk

Fixes #102827
Fixes #103181
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs21
-rw-r--r--src/test/rustdoc/not-wf-ambiguous-normalization.rs24
-rw-r--r--src/test/ui/impl-trait/issue-103181-1.rs85
-rw-r--r--src/test/ui/impl-trait/issue-103181-1.stderr12
-rw-r--r--src/test/ui/impl-trait/issue-103181-2.rs29
-rw-r--r--src/test/ui/impl-trait/issue-103181-2.stderr9
6 files changed, 178 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index aa8094a60dd..715f5be8e2f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -14,6 +14,7 @@ use rustc_infer::traits::Normalized;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_span::DUMMY_SP;
 
 use std::ops::ControlFlow;
 
@@ -253,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // Rustdoc normalizes possibly not well-formed types, so only
+                    // treat this as a bug if we're not in rustdoc.
+                    if !tcx.sess.opts.actually_rustdoc {
+                        tcx.sess.delay_span_bug(
+                            DUMMY_SP,
+                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+                        );
+                    }
+                    return Err(NoSolution);
                 }
                 let InferOk { value: result, obligations } =
                     self.infcx.instantiate_query_response_and_region_obligations(
@@ -296,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // Rustdoc normalizes possibly not well-formed types, so only
+                    // treat this as a bug if we're not in rustdoc.
+                    if !tcx.sess.opts.actually_rustdoc {
+                        tcx.sess.delay_span_bug(
+                            DUMMY_SP,
+                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+                        );
+                    }
+                    return Err(NoSolution);
                 }
                 let InferOk { value: result, obligations } =
                     self.infcx.instantiate_query_response_and_region_obligations(
diff --git a/src/test/rustdoc/not-wf-ambiguous-normalization.rs b/src/test/rustdoc/not-wf-ambiguous-normalization.rs
new file mode 100644
index 00000000000..1e9f925f845
--- /dev/null
+++ b/src/test/rustdoc/not-wf-ambiguous-normalization.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Znormalize-docs
+
+#![feature(type_alias_impl_trait)]
+
+trait Allocator {
+    type Buffer;
+}
+
+struct DefaultAllocator;
+
+// This unconstrained impl parameter causes the normalization of
+// `<DefaultAllocator as Allocator>::Buffer` to be ambiguous,
+// which caused an ICE with `-Znormalize-docs`.
+impl<T> Allocator for DefaultAllocator {
+    type Buffer = ();
+}
+
+type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
+
+fn foo() -> A {
+    |_| ()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-1.rs b/src/test/ui/impl-trait/issue-103181-1.rs
new file mode 100644
index 00000000000..197aedf9d98
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-1.rs
@@ -0,0 +1,85 @@
+// edition:2021
+
+mod hyper {
+    use std::{fmt::Debug, future::Future, marker::PhantomData, pin::Pin, task::Poll};
+
+    pub trait HttpBody {
+        type Error;
+    }
+    impl HttpBody for () {
+        //~^ ERROR not all trait items implemented, missing: `Error`
+        // don't implement `Error` here for the ICE
+    }
+
+    pub struct Server<I, S>(I, S);
+
+    pub fn serve<I, S>(_: S) -> Server<I, S> {
+        todo!()
+    }
+
+    impl<S, B> Future for Server<(), S>
+    where
+        S: MakeServiceRef<(), (), ResBody = B>,
+        B: HttpBody,
+        B::Error: Debug,
+    {
+        type Output = ();
+
+        fn poll(self: Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+            todo!()
+        }
+    }
+
+    pub trait MakeServiceRef<Target, ReqBody> {
+        type ResBody;
+    }
+
+    impl<T, S> MakeServiceRef<(), ()> for T
+    where
+        T: for<'a> Service<&'a (), Response = S>,
+        S: Service<()>,
+    {
+        type ResBody = ();
+    }
+
+    pub struct MakeServiceFn<F>(pub F);
+    pub struct ServiceFn<F, R>(pub PhantomData<(F, R)>);
+
+    pub trait Service<Request> {
+        type Response;
+    }
+
+    impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F>
+    where
+        F: Fn() -> Ret,
+        Ret: Future<Output = Result<Svc, ()>>,
+    {
+        type Response = Svc;
+    }
+
+    impl<F, ReqBody, Ret, ResBody, E> Service<ReqBody> for ServiceFn<F, ReqBody>
+    where
+        F: Fn() -> Ret,
+        Ret: Future<Output = Result<ResBody, E>>,
+    {
+        type Response = ResBody;
+    }
+}
+
+async fn smarvice() -> Result<(), ()> {
+    Ok(())
+}
+
+fn service_fn<F, R, S>(f: F) -> hyper::ServiceFn<F, R>
+where
+    F: Fn() -> S,
+{
+    hyper::ServiceFn(std::marker::PhantomData)
+}
+
+async fn iceice() {
+    let service = hyper::MakeServiceFn(|| async { Ok::<_, ()>(service_fn(|| smarvice())) });
+    hyper::serve::<(), _>(service).await;
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-1.stderr b/src/test/ui/impl-trait/issue-103181-1.stderr
new file mode 100644
index 00000000000..cd026607d52
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-1.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `Error`
+  --> $DIR/issue-103181-1.rs:9:5
+   |
+LL |         type Error;
+   |         ---------- `Error` from trait
+LL |     }
+LL |     impl HttpBody for () {
+   |     ^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/impl-trait/issue-103181-2.rs b/src/test/ui/impl-trait/issue-103181-2.rs
new file mode 100644
index 00000000000..b43ac45075e
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-2.rs
@@ -0,0 +1,29 @@
+// edition:2021
+
+trait SendFuture: Send {
+    type Output;
+}
+
+impl<Fut: Send> SendFuture for Fut {
+    type Output = ();
+}
+
+async fn broken_fut() {
+    ident_error;
+    //~^ ERROR cannot find value `ident_error` in this scope
+}
+
+// triggers normalization of `<Fut as SendFuture>::Output`,
+// which requires `Fut: Send`.
+fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {}
+
+async fn iceice<A, B>()
+// <- async fn is necessary
+where
+    A: Send,
+    B: Send, // <- a second bound
+{
+    normalize(broken_fut(), ());
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-2.stderr b/src/test/ui/impl-trait/issue-103181-2.stderr
new file mode 100644
index 00000000000..5eb2dd9184b
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-2.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `ident_error` in this scope
+  --> $DIR/issue-103181-2.rs:12:5
+   |
+LL |     ident_error;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.