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
This commit is contained in:
Matthias Krüger 2022-10-23 08:14:32 +02:00 committed by GitHub
commit 72f75d18b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 2 deletions

View File

@ -14,6 +14,7 @@
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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
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(

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.