-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Ensure no type errors when calling Closure/Generator upvars_ty #78392
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS}; | |
use polonius_engine::Atom; | ||
use rustc_ast as ast; | ||
use rustc_data_structures::captures::Captures; | ||
use rustc_errors::ErrorReported; | ||
use rustc_hir as hir; | ||
use rustc_hir::def_id::DefId; | ||
use rustc_index::vec::Idx; | ||
|
@@ -388,15 +389,23 @@ impl<'tcx> ClosureSubsts<'tcx> { | |
self.split().parent_substs | ||
} | ||
|
||
/// Returns an iterator that iterates the types of paths captured by a closure. | ||
/// Note it's possible that there was a type error that prevented us from figuring out | ||
/// the types of the upvars captured by the closure. | ||
/// | ||
/// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. | ||
#[inline] | ||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { | ||
self.tupled_upvars_ty().tuple_fields() | ||
self.split().tupled_upvars_ty.expect_ty().tuple_fields() | ||
} | ||
|
||
/// Returns the tuple type representing the upvars for this closure. | ||
/// Returns a tuple type containing the types of paths captured by the closure. | ||
/// Returns Err(ErrorReported) if a type error prevented us from figuring out | ||
/// the types of the upvars for this closure. | ||
#[inline] | ||
pub fn tupled_upvars_ty(self) -> Ty<'tcx> { | ||
self.split().tupled_upvars_ty.expect_ty() | ||
pub fn tupled_upvars_ty(self) -> Result<Ty<'tcx>, ErrorReported> { | ||
let tupled_ty = self.split().tupled_upvars_ty.expect_ty(); | ||
if let TyKind::Error(_) = tupled_ty.kind() { Err(ErrorReported) } else { Ok(tupled_ty) } | ||
} | ||
|
||
/// Returns the closure kind for this closure; may return a type | ||
|
@@ -515,15 +524,23 @@ impl<'tcx> GeneratorSubsts<'tcx> { | |
self.split().witness.expect_ty() | ||
} | ||
|
||
/// Returns an iterator that iterates the types of paths captured by a generator. | ||
/// Note it's possible that there was a type error that prevented us from figuring out | ||
/// the types of the upvars captured by the generator. | ||
/// | ||
/// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. | ||
#[inline] | ||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { | ||
self.tupled_upvars_ty().tuple_fields() | ||
self.split().tupled_upvars_ty.expect_ty().tuple_fields() | ||
} | ||
|
||
/// Returns the tuple type representing the upvars for this generator. | ||
/// Returns a tuple type containing the types of paths captured by the generator. | ||
/// Returns Err(ErrorReported) if a type error prevented us from figuring out | ||
/// the types of the upvars for this generator. | ||
#[inline] | ||
pub fn tupled_upvars_ty(self) -> Ty<'tcx> { | ||
self.split().tupled_upvars_ty.expect_ty() | ||
pub fn tupled_upvars_ty(self) -> Result<Ty<'tcx>, ErrorReported> { | ||
let tupled_ty = self.split().tupled_upvars_ty.expect_ty(); | ||
if let TyKind::Error(_) = tupled_ty.kind() { Err(ErrorReported) } else { Ok(tupled_ty) } | ||
} | ||
|
||
/// Returns the type representing the resume type of the generator. | ||
|
@@ -660,6 +677,11 @@ pub enum UpvarSubsts<'tcx> { | |
} | ||
|
||
impl<'tcx> UpvarSubsts<'tcx> { | ||
/// Returns an iterator that iterates the types of paths captured by a closure/generator. | ||
/// Note it's possible that there was a type error that prevented us from figuring out | ||
/// the types of the upvars captured by the closure/generator. | ||
/// | ||
/// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. | ||
#[inline] | ||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { | ||
let tupled_upvars_ty = match self { | ||
|
@@ -669,8 +691,11 @@ impl<'tcx> UpvarSubsts<'tcx> { | |
tupled_upvars_ty.expect_ty().tuple_fields() | ||
} | ||
|
||
/// Returns a tuple type containing the types of paths captured by a closure/generator. | ||
/// Returns Err(ErrorReported) if a type error prevented us from figuring out | ||
/// the types of the upvars for this closure/generator. | ||
#[inline] | ||
pub fn tupled_upvars_ty(self) -> Ty<'tcx> { | ||
pub fn tupled_upvars_ty(self) -> Result<Ty<'tcx>, ErrorReported> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pre-existing to some extent, but I think this function merits a comment. Something like: Returns a tuple type whose elements are the types of the upvars captured by this closure/generator. Returns |
||
match self { | ||
UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(), | ||
UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1601,12 +1601,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
|
||
ty::Closure(_, substs) => { | ||
// (*) binder moved here | ||
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); | ||
if let ty::Infer(ty::TyVar(_)) = ty.kind() { | ||
// Not yet resolved. | ||
Ambiguous | ||
|
||
if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: it feels like we may want a helper for this pattern of shallow resolving the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see too much benefit here, especially since each case Tuple/Infer/Error will need to be handled at each call site. Also, we only do this in 3 spots. |
||
let ty = self.infcx.shallow_resolve(tupled_tys); | ||
if let ty::Infer(ty::TyVar(_)) = ty.kind() { | ||
// Not yet resolved. | ||
Ambiguous | ||
} else { | ||
Where( | ||
obligation.predicate.rebind(substs.as_closure().upvar_tys().collect()), | ||
) | ||
} | ||
} else { | ||
Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect())) | ||
Where(ty::Binder::dummy(Vec::new())) | ||
} | ||
} | ||
|
||
|
@@ -1677,14 +1684,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
} | ||
|
||
ty::Closure(_, ref substs) => { | ||
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); | ||
vec![ty] | ||
if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { | ||
let ty = self.infcx.shallow_resolve(tupled_tys); | ||
vec![ty] | ||
} else { | ||
vec![] | ||
} | ||
} | ||
|
||
ty::Generator(_, ref substs, _) => { | ||
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); | ||
let tys_vec = if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { | ||
let ty = self.infcx.shallow_resolve(tupled_tys); | ||
vec![ty] | ||
} else { | ||
vec![] | ||
}; | ||
let witness = substs.as_generator().witness(); | ||
vec![ty].into_iter().chain(iter::once(witness)).collect() | ||
tys_vec.into_iter().chain(iter::once(witness)).collect() | ||
} | ||
|
||
ty::GeneratorWitness(types) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think this function merits a comment too. Something like
That said, this will still ICE in the event of a
Ty::Err
, right? I'm not sure if that's a great idea, as it means that every use of this function has to be guarded by a call totupled_upvars_ty
. Why not make this function return aResult
as well (or perhaps an empty vector)?