Eagerly instantiate closure ty

This commit is contained in:
Michael Goulet 2024-01-14 02:00:45 +00:00
parent 098d4fd74c
commit 37a5464bc8
4 changed files with 73 additions and 79 deletions

View File

@ -68,12 +68,58 @@ pub fn check_expr_closure(
debug!(?bound_sig, ?liberated_sig); debug!(?bound_sig, ?liberated_sig);
let parent_args =
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
// FIXME: We could probably actually just unify this further -- // FIXME: We could probably actually just unify this further --
// instead of having a `FnSig` and a `Option<CoroutineTypes>`, // instead of having a `FnSig` and a `Option<CoroutineTypes>`,
// we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`, // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
// similar to how `ty::GenSig` is a distinct data structure. // similar to how `ty::GenSig` is a distinct data structure.
let coroutine_types = match closure.kind { let (closure_ty, coroutine_types) = match closure.kind {
hir::ClosureKind::Closure => None, hir::ClosureKind::Closure => {
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
let sig = bound_sig.map_bound(|sig| {
tcx.mk_fn_sig(
[Ty::new_tup(tcx, sig.inputs())],
sig.output(),
sig.c_variadic,
sig.unsafety,
sig.abi,
)
});
debug!(?sig, ?expected_kind);
let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
None => self.next_root_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
}),
};
let closure_args = ty::ClosureArgs::new(
tcx,
ty::ClosureArgsParts {
parent_args,
closure_kind_ty,
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
tupled_upvars_ty,
},
);
(Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None)
}
hir::ClosureKind::Coroutine(kind) => { hir::ClosureKind::Coroutine(kind) => {
let yield_ty = match kind { let yield_ty = match kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
@ -119,74 +165,6 @@ pub fn check_expr_closure(
// Resume type defaults to `()` if the coroutine has no argument. // Resume type defaults to `()` if the coroutine has no argument.
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
Some(CoroutineTypes { resume_ty, yield_ty })
}
};
check_fn(
&mut FnCtxt::new(self, self.param_env, closure.def_id),
liberated_sig,
coroutine_types,
closure.fn_decl,
expr_def_id,
body,
// Closure "rust-call" ABI doesn't support unsized params
false,
);
let parent_args =
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
match closure.kind {
hir::ClosureKind::Closure => {
assert_eq!(coroutine_types, None);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
let sig = bound_sig.map_bound(|sig| {
tcx.mk_fn_sig(
[Ty::new_tup(tcx, sig.inputs())],
sig.output(),
sig.c_variadic,
sig.unsafety,
sig.abi,
)
});
debug!(?sig, ?expected_kind);
let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
None => self.next_root_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
}),
};
let closure_args = ty::ClosureArgs::new(
tcx,
ty::ClosureArgsParts {
parent_args,
closure_kind_ty,
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
tupled_upvars_ty,
},
);
Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
}
hir::ClosureKind::Coroutine(_) => {
let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
bug!("expected coroutine to have yield/resume types");
};
let interior = self.next_ty_var(TypeVariableOrigin { let interior = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable, kind: TypeVariableOriginKind::MiscVariable,
span: body.value.span, span: body.value.span,
@ -209,9 +187,25 @@ pub fn check_expr_closure(
}, },
); );
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args) (
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args),
Some(CoroutineTypes { resume_ty, yield_ty }),
)
} }
} };
check_fn(
&mut FnCtxt::new(self, self.param_env, closure.def_id),
liberated_sig,
coroutine_types,
closure.fn_decl,
expr_def_id,
body,
// Closure "rust-call" ABI doesn't support unsized params
false,
);
closure_ty
} }
/// Given the expected type, figures out what it can about this closure we /// Given the expected type, figures out what it can about this closure we
@ -683,10 +677,10 @@ fn supplied_sig_of_closure(
}) })
} }
// All `gen {}` and `async gen {}` must return unit. // All `gen {}` and `async gen {}` must return unit.
hir::ClosureKind::Coroutine( hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen,
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), _,
) => self.tcx.types.unit, )) => self.tcx.types.unit,
// For async blocks, we just fall back to `_` here. // For async blocks, we just fall back to `_` here.
// For closures/coroutines, we know nothing about the return // For closures/coroutines, we know nothing about the return

View File

@ -9,7 +9,7 @@ LL | let c1 : () = c;
| expected due to this | expected due to this
| |
= note: expected unit type `()` = note: expected unit type `()`
found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
help: use parentheses to call this closure help: use parentheses to call this closure
| |
LL | let c1 : () = c(); LL | let c1 : () = c();

View File

@ -9,7 +9,7 @@ LL | let c1 : () = c;
| expected due to this | expected due to this
| |
= note: expected unit type `()` = note: expected unit type `()`
found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
help: use parentheses to call this closure help: use parentheses to call this closure
| |
LL | let c1 : () = c(); LL | let c1 : () = c();

View File

@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
| expected due to this | expected due to this
| |
= note: expected fn pointer `fn(u8) -> u8` = note: expected fn pointer `fn(u8) -> u8`
found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]}` found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}`
note: closures can only be coerced to `fn` types if they do not capture any variables note: closures can only be coerced to `fn` types if they do not capture any variables
--> $DIR/closure-print-verbose.rs:10:39 --> $DIR/closure-print-verbose.rs:10:39
| |