Skip to content

Commit

Permalink
Do not record unresolved const vars in generator interior
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Nov 26, 2022
1 parent aff003b commit 6210812
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 43 deletions.
14 changes: 7 additions & 7 deletions compiler/rustc_hir_typeck/src/generator_interior/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr, scope, ty, self.expr_count, yield_data.span
);

if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty)
if let Some((unresolved_term, unresolved_type_span)) =
self.fcx.first_unresolved_const_or_ty_var(&ty)
{
// If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self
Expand All @@ -108,21 +108,21 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {

// If we encounter an int/float variable, then inference fallback didn't
// finish due to some other error. Don't emit spurious additional errors.
if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) =
unresolved_type.kind()
if let Some(unresolved_ty) = unresolved_term.ty()
&& let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind()
{
self.fcx
.tcx
.sess
.delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type));
.delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
} else {
let note = format!(
"the type is part of the {} because of this {}",
self.kind, yield_data.source
);

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)
.emit();
}
Expand Down Expand Up @@ -162,7 +162,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr.map(|e| e.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!(
"remained unresolved_type = {:?}, unresolved_type_span: {:?}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
kind: hir::GeneratorKind,
span: Span,
ty: Ty<'tcx>,
ty: ty::Term<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ty = self.resolve_vars_if_possible(ty);
let data = self.extract_inference_diagnostics_data(ty.into(), None);
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,16 +1421,15 @@ impl<'tcx> InferCtxt<'tcx> {
value.fold_with(&mut r)
}

/// Returns the first unresolved variable contained in `T`. In the
/// process of visiting `T`, this will resolve (where possible)
/// type variables in `T`, but it never constructs the final,
/// resolved type, so it's more efficient than
/// `resolve_vars_if_possible()`.
pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
/// Returns the first unresolved type or const variable contained in `T`.
pub fn first_unresolved_const_or_ty_var<T>(
&self,
value: &T,
) -> Option<(ty::Term<'tcx>, Option<Span>)>
where
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(
Expand Down
86 changes: 58 additions & 28 deletions compiler/rustc_infer/src/infer/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
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::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
Expand Down Expand Up @@ -110,48 +111,77 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
/// 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
/// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'tcx> {
pub struct UnresolvedTypeOrConstFinder<'a, '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 {
UnresolvedTypeFinder { infcx }
UnresolvedTypeOrConstFinder { infcx }
}
}

impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
type BreakTy = (Ty<'tcx>, Option<Span>);
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
type BreakTy = (ty::Term<'tcx>, Option<Span>);
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() {
if let ty::Infer(infer_ty) = *t.kind() {
// Since we called `shallow_resolve` above, this must
// be an (as yet...) unresolved inference variable.
let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
let mut inner = self.infcx.inner.borrow_mut();
let ty_vars = &inner.type_variables();
if let TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
span,
} = *ty_vars.var_origin(ty_vid)
{
Some(span)
} else {
None
}
if let ty::Infer(infer_ty) = *t.kind() {
// Since we called `shallow_resolve` above, this must
// be an (as yet...) unresolved inference variable.
let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
let mut inner = self.infcx.inner.borrow_mut();
let ty_vars = &inner.type_variables();
if let TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
span,
} = *ty_vars.var_origin(ty_vid)
{
Some(span)
} else {
None
};
ControlFlow::Break((t, ty_var_span))
}
} else {
// Otherwise, visit its contents.
t.super_visit_with(self)
}
None
};
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 {
// All type variables in inference types must already be resolved,
// - no need to visit the contents, continue visiting.
// Otherwise, keep visiting.
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 {
None
}
} 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
} else {
// Otherwise, keep visiting.
ct.super_visit_with(self)
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
#[inline]
pub fn unpack(self) -> GenericArgKind<'tcx> {
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/generator/unresolved-ct-var.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 78 additions & 0 deletions src/test/ui/generator/unresolved-ct-var.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 6210812

Please sign in to comment.