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:
commit
e6c83d9e42
7 changed files with 174 additions and 44 deletions
|
@ -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: {:?}",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
14
src/test/ui/generator/unresolved-ct-var.rs
Normal file
14
src/test/ui/generator/unresolved-ct-var.rs
Normal 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
|
||||||
|
};
|
||||||
|
}
|
78
src/test/ui/generator/unresolved-ct-var.stderr
Normal file
78
src/test/ui/generator/unresolved-ct-var.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue