Skip to content

Commit

Permalink
Rollup merge of #103368 - compiler-errors:normalization-ambiguity-bug…
Browse files Browse the repository at this point in the history
…, 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
  • Loading branch information
matthiaskrgr committed Oct 23, 2022
2 parents ff689a1 + cb61113 commit 72f75d1
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 2 deletions.
21 changes: 19 additions & 2 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
24 changes: 24 additions & 0 deletions src/test/rustdoc/not-wf-ambiguous-normalization.rs
Original file line number Diff line number Diff line change
@@ -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() {}
85 changes: 85 additions & 0 deletions src/test/ui/impl-trait/issue-103181-1.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions src/test/ui/impl-trait/issue-103181-1.stderr
Original file line number Diff line number Diff line change
@@ -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`.
29 changes: 29 additions & 0 deletions src/test/ui/impl-trait/issue-103181-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions src/test/ui/impl-trait/issue-103181-2.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 72f75d1

Please sign in to comment.