1
Fork 0

Rollup merge of #104788 - compiler-errors:unresolved-ct-in-gen, r=fee1-dead

Do not record unresolved const vars in generator interior

Don't record types in the generator interior when we see unresolved const variables.

We already do this for associated types -- this is important to avoid unresolved inference variables in the generator results during writeback, since the writeback results get stable hashed in incremental mode.

Fixes #104787
This commit is contained in:
Guillaume Gomez 2022-11-26 17:47:23 +01:00 committed by GitHub
commit e6c83d9e42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 44 deletions

View file

@ -98,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr, scope, ty, self.expr_count, yield_data.span expr, scope, ty, self.expr_count, yield_data.span
); );
if let Some((unresolved_type, unresolved_type_span)) = if let Some((unresolved_term, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty) self.fcx.first_unresolved_const_or_ty_var(&ty)
{ {
// If unresolved type isn't a ty_var then unresolved_type_span is None // If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self let span = self
@ -108,13 +108,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
// If we encounter an int/float variable, then inference fallback didn't // If we encounter an int/float variable, then inference fallback didn't
// finish due to some other error. Don't emit spurious additional errors. // finish due to some other error. Don't emit spurious additional errors.
if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = if let Some(unresolved_ty) = unresolved_term.ty()
unresolved_type.kind() && let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind()
{ {
self.fcx self.fcx
.tcx .tcx
.sess .sess
.delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type)); .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
} else { } else {
let note = format!( let note = format!(
"the type is part of the {} because of this {}", "the type is part of the {} because of this {}",
@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
); );
self.fcx self.fcx
.need_type_info_err_in_generator(self.kind, span, unresolved_type) .need_type_info_err_in_generator(self.kind, span, unresolved_term)
.span_note(yield_data.span, &*note) .span_note(yield_data.span, &*note)
.emit(); .emit();
} }
@ -162,7 +162,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr.map(|e| e.span) expr.map(|e| e.span)
); );
if let Some((unresolved_type, unresolved_type_span)) = if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty) self.fcx.first_unresolved_const_or_ty_var(&ty)
{ {
debug!( debug!(
"remained unresolved_type = {:?}, unresolved_type_span: {:?}", "remained unresolved_type = {:?}, unresolved_type_span: {:?}",

View file

@ -568,7 +568,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self, &self,
kind: hir::GeneratorKind, kind: hir::GeneratorKind,
span: Span, span: Span,
ty: Ty<'tcx>, ty: ty::Term<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
let data = self.extract_inference_diagnostics_data(ty.into(), None); let data = self.extract_inference_diagnostics_data(ty.into(), None);

View file

@ -1421,16 +1421,15 @@ impl<'tcx> InferCtxt<'tcx> {
value.fold_with(&mut r) value.fold_with(&mut r)
} }
/// Returns the first unresolved variable contained in `T`. In the /// Returns the first unresolved type or const variable contained in `T`.
/// process of visiting `T`, this will resolve (where possible) pub fn first_unresolved_const_or_ty_var<T>(
/// type variables in `T`, but it never constructs the final, &self,
/// resolved type, so it's more efficient than value: &T,
/// `resolve_vars_if_possible()`. ) -> Option<(ty::Term<'tcx>, Option<Span>)>
pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
where where
T: TypeVisitable<'tcx>, T: TypeVisitable<'tcx>,
{ {
value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value()
} }
pub fn probe_const_var( pub fn probe_const_var(

View file

@ -1,5 +1,6 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span}; use super::{FixupError, FixupResult, InferCtxt, Span};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@ -110,21 +111,20 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
/// type variables that don't yet have a value. The first unresolved type is stored. /// type variables that don't yet have a value. The first unresolved type is stored.
/// It does not construct the fully resolved type (which might /// It does not construct the fully resolved type (which might
/// involve some hashing and so forth). /// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'tcx> { pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>, infcx: &'a InferCtxt<'tcx>,
} }
impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
UnresolvedTypeFinder { infcx } UnresolvedTypeOrConstFinder { infcx }
} }
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
type BreakTy = (Ty<'tcx>, Option<Span>); type BreakTy = (ty::Term<'tcx>, Option<Span>);
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let t = self.infcx.shallow_resolve(t); let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() {
if let ty::Infer(infer_ty) = *t.kind() { if let ty::Infer(infer_ty) = *t.kind() {
// Since we called `shallow_resolve` above, this must // Since we called `shallow_resolve` above, this must
// be an (as yet...) unresolved inference variable. // be an (as yet...) unresolved inference variable.
@ -143,15 +143,45 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
} else { } else {
None None
}; };
ControlFlow::Break((t, ty_var_span)) ControlFlow::Break((t.into(), ty_var_span))
} else if !t.has_non_region_infer() {
// All const/type variables in inference types must already be resolved,
// no need to visit the contents.
ControlFlow::CONTINUE
} else { } else {
// Otherwise, visit its contents. // Otherwise, keep visiting.
t.super_visit_with(self) t.super_visit_with(self)
} }
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let ct = self.infcx.shallow_resolve(ct);
if let ty::ConstKind::Infer(i) = ct.kind() {
// Since we called `shallow_resolve` above, this must
// be an (as yet...) unresolved inference variable.
let ct_var_span = if let ty::InferConst::Var(vid) = i {
let mut inner = self.infcx.inner.borrow_mut();
let ct_vars = &mut inner.const_unification_table();
if let ConstVariableOrigin {
span,
kind: ConstVariableOriginKind::ConstParameterDefinition(_, _),
} = ct_vars.probe_value(vid).origin
{
Some(span)
} else { } else {
// All type variables in inference types must already be resolved, None
// - no need to visit the contents, continue visiting. }
} else {
None
};
ControlFlow::Break((ct.into(), ct_var_span))
} else if !ct.has_non_region_infer() {
// All const/type variables in inference types must already be resolved,
// no need to visit the contents.
ControlFlow::CONTINUE ControlFlow::CONTINUE
} else {
// Otherwise, keep visiting.
ct.super_visit_with(self)
} }
} }
} }

View file

@ -140,6 +140,15 @@ impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
} }
} }
impl<'tcx> From<ty::Term<'tcx>> for GenericArg<'tcx> {
fn from(value: ty::Term<'tcx>) -> Self {
match value.unpack() {
ty::TermKind::Ty(t) => t.into(),
ty::TermKind::Const(c) => c.into(),
}
}
}
impl<'tcx> GenericArg<'tcx> { impl<'tcx> GenericArg<'tcx> {
#[inline] #[inline]
pub fn unpack(self) -> GenericArgKind<'tcx> { pub fn unpack(self) -> GenericArgKind<'tcx> {

View file

@ -0,0 +1,14 @@
// incremental
// edition:2021
fn main() {
let _ = async {
let s = std::array::from_fn(|_| ()).await;
//~^ ERROR `[(); _]` is not a future
//~| ERROR type inside `async` block must be known in this context
//~| ERROR type inside `async` block must be known in this context
//~| ERROR type inside `async` block must be known in this context
//~| ERROR type inside `async` block must be known in this context
//~| ERROR type inside `async` block must be known in this context
};
}

View file

@ -0,0 +1,78 @@
error[E0277]: `[(); _]` is not a future
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ---------------------------^^^^^^
| | |
| | `[(); _]` is not a future
| | help: remove the `.await`
| this call returns `[(); _]`
|
= help: the trait `Future` is not implemented for `[(); _]`
= note: [(); _] must be a future or must implement `IntoFuture` to be awaited
= note: required for `[(); _]` to implement `IntoFuture`
error[E0698]: type inside `async` block must be known in this context
--> $DIR/unresolved-ct-var.rs:6:17
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
|
note: the type is part of the `async` block because of this `await`
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^
error[E0698]: type inside `async` block must be known in this context
--> $DIR/unresolved-ct-var.rs:6:17
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
|
note: the type is part of the `async` block because of this `await`
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^
error[E0698]: type inside `async` block must be known in this context
--> $DIR/unresolved-ct-var.rs:6:17
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
|
note: the type is part of the `async` block because of this `await`
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^
error[E0698]: type inside `async` block must be known in this context
--> $DIR/unresolved-ct-var.rs:6:17
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
|
note: the type is part of the `async` block because of this `await`
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^
error[E0698]: type inside `async` block must be known in this context
--> $DIR/unresolved-ct-var.rs:6:17
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
|
note: the type is part of the `async` block because of this `await`
--> $DIR/unresolved-ct-var.rs:6:44
|
LL | let s = std::array::from_fn(|_| ()).await;
| ^^^^^^
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0277, E0698.
For more information about an error, try `rustc --explain E0277`.