Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace tuple of infer vars for upvar_tys with single infer var #77873

Merged
merged 4 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/rustc_middle/src/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,14 @@ fn compute_components(
}

ty::Closure(_, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
}
let tupled_ty = substs.as_closure().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
}

ty::Generator(_, ref substs, _) => {
// Same as the closure case
for upvar_ty in substs.as_generator().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
}
let tupled_ty = substs.as_generator().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);

// We ignore regions in the generator interior as we don't
// want these to affect region inference
Expand Down
46 changes: 17 additions & 29 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>:
}
} else {
p!(print_def_path(did, substs));
if substs.as_generator().is_valid() {
// Search for the first inference variable
p!(" upvar_tys=(");
let mut uninferred_ty =
substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
if uninferred_ty.next().is_some() {
p!(write("unavailable"));
} else {
self = self.comma_sep(substs.as_generator().upvar_tys())?;
}
p!(")");
p!(" upvar_tys=(");
if !substs.as_generator().is_valid() {
p!("unavailable");
} else {
self = self.comma_sep(substs.as_generator().upvar_tys())?;
}
p!(")");
roxelo marked this conversation as resolved.
Show resolved Hide resolved
}

if substs.as_generator().is_valid() {
Expand Down Expand Up @@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>:
}
} else {
p!(print_def_path(did, substs));
if substs.as_closure().is_valid() {
// Search for the first inference variable
let mut uninferred_ty =
substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer());
if uninferred_ty.next().is_some() {
// If the upvar substs contain an inference variable we haven't
// finished capture analysis.
p!(" closure_substs=(unavailable)");
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
" closure_sig_as_fn_ptr_ty=",
print(substs.as_closure().sig_as_fn_ptr_ty())
);
p!(" upvar_tys=(");
self = self.comma_sep(substs.as_closure().upvar_tys())?;
p!(")");
}
if !substs.as_closure().is_valid() {
p!(" closure_substs=(unavailable)");
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
" closure_sig_as_fn_ptr_ty=",
print(substs.as_closure().sig_as_fn_ptr_ty())
);
p!(" upvar_tys=(");
self = self.comma_sep(substs.as_closure().upvar_tys())?;
p!(")");
}
}
p!("]");
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> {
};
tupled_upvars_ty.expect_ty().tuple_fields()
}

#[inline]
pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
match self {
UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
}
}
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_trait_selection/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,8 @@ where
ty::Closure(_, ref substs) => {
// Skip lifetime parameters of the enclosing item(s)

substs.as_closure().tupled_upvars_ty().visit_with(self);

for upvar_ty in substs.as_closure().upvar_tys() {
upvar_ty.visit_with(self);
}
Expand All @@ -728,6 +730,8 @@ where
// Skip lifetime parameters of the enclosing item(s)
// Also skip the witness type, because that has no free regions.

substs.as_generator().tupled_upvars_ty().visit_with(self);

for upvar_ty in substs.as_generator().upvar_tys() {
upvar_ty.visit_with(self);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut generator = None;
let mut outer_generator = None;
let mut next_code = Some(&obligation.cause.code);

let mut seen_upvar_tys_infer_tuple = false;

while let Some(code) = next_code {
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
Expand All @@ -1327,6 +1330,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
outer_generator = Some(did);
}
ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself,
// we shall ignore this.

seen_upvar_tys_infer_tuple = true;
}
_ if generator.is_none() => {
trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
target_ty = Some(ty);
Expand Down Expand Up @@ -1912,7 +1922,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}

err.note(&format!("required because it appears within the type `{}`", ty));
// If the obligation for a tuple is set directly by a Generator or Closure,
// then the tuple must be the one containing capture types.
let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
false
} else {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
*data.parent_code
{
let parent_trait_ref =
self.resolve_vars_if_possible(&data.parent_trait_ref);
let ty = parent_trait_ref.skip_binder().self_ty();
matches!(ty.kind(), ty::Generator(..))
|| matches!(ty.kind(), ty::Closure(..))
} else {
false
}
};

// Don't print the tuple of capture types
if !is_upvar_tys_infer_tuple {
err.note(&format!("required because it appears within the type `{}`", ty));
}

obligated_types.push(ty);

let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
// check if *any* of those are trivial.
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
ty::Closure(_, ref substs) => {
substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
}

ty::Adt(def, _) => {
Expand Down
16 changes: 13 additions & 3 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1631,7 +1631,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

ty::Closure(_, substs) => {
// (*) binder moved here
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
// Not yet resolved.
Ambiguous
} else {
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
}
}

ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
Expand Down Expand Up @@ -1700,11 +1706,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
tys.iter().map(|k| k.expect_ty()).collect()
}

ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
ty::Closure(_, ref substs) => {
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
vec![ty]
}

ty::Generator(_, ref substs, _) => {
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
let witness = substs.as_generator().witness();
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
vec![ty].into_iter().chain(iter::once(witness)).collect()
}

ty::GeneratorWitness(types) => {
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// anyway, except via auto trait matching (which
// only inspects the upvar types).
walker.skip_current_subtree(); // subtree handled below
for upvar_ty in substs.as_closure().upvar_tys() {
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(upvar_ty.into());
}
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(substs.as_closure().tupled_upvars_ty().into());
}

ty::FnPtr(_) => {
Expand Down
33 changes: 28 additions & 5 deletions compiler/rustc_traits/src/dropck_outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,25 @@ fn dtorck_constraint_for_ty<'tcx>(
Ok::<_, NoSolution>(())
})?,

ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in substs.as_closure().upvar_tys() {
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
ty::Closure(_, substs) => {
if !substs.as_closure().is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.

tcx.sess.delay_span_bug(
span,
&format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,),
);
return Err(NoSolution);
roxelo marked this conversation as resolved.
Show resolved Hide resolved
}
Ok::<_, NoSolution>(())
})?,

rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in substs.as_closure().upvar_tys() {
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
}
Ok::<_, NoSolution>(())
})?
}

ty::Generator(_, substs, _movability) => {
// rust-lang/rust#49918: types can be constructed, stored
Expand All @@ -241,6 +254,16 @@ fn dtorck_constraint_for_ty<'tcx>(
// derived from lifetimes attached to the upvars and resume
// argument, and we *do* incorporate those here.

if !substs.as_generator().is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
tcx.sess.delay_span_bug(
span,
&format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,),
);
return Err(NoSolution);
roxelo marked this conversation as resolved.
Show resolved Hide resolved
}

constraints.outlives.extend(
substs
.as_generator()
Expand Down
17 changes: 4 additions & 13 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
);

let tupled_upvars_ty =
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
upvars.iter().map(|(&var_hir_id, _)| {
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`).
self.infcx.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish upvar inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(var_hir_id),
})
})
}));
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(expr.hir_id),
});

if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
{
Expand Down
23 changes: 18 additions & 5 deletions compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::astconv::AstConv;
use crate::check::FnCtxt;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_middle::ty::adjustment::{
Expand Down Expand Up @@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
ty::Closure(_, substs_a) => {
ty::Closure(closure_def_id_a, substs_a) => {
// Non-capturing closures are coercible to
// function pointers or unsafe function pointers.
// It cannot convert closures that require unsafe.
self.coerce_closure_to_fn(a, substs_a, b)
self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
}
_ => {
// Otherwise, just use unification rules.
Expand Down Expand Up @@ -762,6 +763,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn coerce_closure_to_fn(
&self,
a: Ty<'tcx>,
closure_def_id_a: DefId,
substs_a: SubstsRef<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
Expand All @@ -772,7 +774,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let b = self.shallow_resolve(b);

match b.kind() {
ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
// At this point we haven't done capture analysis, which means
// that the ClosureSubsts just contains an inference variable instead
// of tuple of captured types.
//
// All we care here is if any variable is being captured and not the exact paths,
// so we check `upvars_mentioned` for root variables being captured.
ty::FnPtr(fn_ty)
if self
.tcx
.upvars_mentioned(closure_def_id_a.expect_local())
.map_or(true, |u| u.is_empty()) =>
{
// We coerce the closure, which has fn type
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
// to
Expand Down Expand Up @@ -906,8 +919,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Function items or non-capturing closures of differing IDs or InternalSubsts.
let (a_sig, b_sig) = {
let is_capturing_closure = |ty| {
if let &ty::Closure(_, substs) = ty {
substs.as_closure().upvar_tys().next().is_some()
if let &ty::Closure(closure_def_id, _substs) = ty {
self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
} else {
false
}
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
closure_hir_id, substs, final_upvar_tys
);
for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) {
self.demand_suptype(span, upvar_ty, final_upvar_ty);
}

// Build a tuple (U0..Un) of the final upvar types U0..Un
// and unify the upvar tupe type in the closure with it:
let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);

// If we are also inferred the closure kind here,
// process any deferred resolutions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]`
error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]`
--> $DIR/generator-yielding-or-returning-itself.rs:15:5
|
LL | pub fn want_cyclic_generator_return<T>(_: T)
Expand All @@ -14,7 +14,7 @@ LL | want_cyclic_generator_return(|| {
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
for more information

error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]`
error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]`
--> $DIR/generator-yielding-or-returning-itself.rs:28:5
|
LL | pub fn want_cyclic_generator_yield<T>(_: T)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | assert_send(|| {
|
= help: the trait `Sync` is not implemented for `Cell<i32>`
= note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>`
= note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#16t]`
= note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]`

error: generator cannot be shared between threads safely
--> $DIR/generator-print-verbose-2.rs:12:5
Expand Down
Loading