Random type checker changes

This commit is contained in:
Michael Goulet 2024-01-23 15:10:23 +00:00
parent 021861aea8
commit 5fc39e0796
13 changed files with 59 additions and 93 deletions

View File

@ -12,7 +12,9 @@
#[derive(Copy, Clone, Debug)]
pub enum AutoderefKind {
/// A true pointer type, such as `&T` and `*mut T`.
Builtin,
/// A type which must dispatch to a `Deref` implementation.
Overloaded,
}
@ -83,6 +85,7 @@ fn next(&mut self) -> Option<Self::Item> {
(AutoderefKind::Builtin, ty)
}
} else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
// The overloaded deref check already normalizes the pointee type.
(AutoderefKind::Overloaded, ty)
} else {
return None;

View File

@ -254,7 +254,7 @@ fn compare_method_predicate_entailment<'tcx>(
// checks. For the comparison to be valid, we need to
// normalize the associated types in the impl/trait methods
// first. However, because function types bind regions, just
// calling `normalize_associated_types_in` would have no effect on
// calling `FnCtxt::normalize` would have no effect on
// any associated types appearing in the fn arguments or return
// type.

View File

@ -746,11 +746,13 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use normalize_associated_types_in as it will pollute the
// We can't use `FnCtxt::normalize` as it will pollute the
// fcx's fulfillment context after this probe is over.
//
// Note: we only normalize `xform_self_ty` here since the normalization
// of the return type can lead to inference results that prohibit
// valid candidates from being found, see issue #85671
//
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
// which might be caused by the `param_env` itself. The clauses of the `param_env`
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,

View File

@ -804,17 +804,12 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
}
} else {
p!(print_def_path(did, args));
p!(" upvar_tys=(");
if !args.as_coroutine().is_valid() {
p!("unavailable");
} else {
self.comma_sep(args.as_coroutine().upvar_tys().iter())?;
}
p!(")");
if args.as_coroutine().is_valid() {
p!(" ", print(args.as_coroutine().witness()));
}
p!(
" upvar_tys=",
print(args.as_coroutine().tupled_upvars_ty()),
" witness=",
print(args.as_coroutine().witness())
);
}
p!("}}")
@ -868,19 +863,14 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
}
} else {
p!(print_def_path(did, args));
if !args.as_closure().is_valid() {
p!(" closure_args=(unavailable)");
p!(write(" args={}", args.print_as_list()));
} else {
p!(" closure_kind_ty=", print(args.as_closure().kind_ty()));
p!(
" closure_sig_as_fn_ptr_ty=",
print(args.as_closure().sig_as_fn_ptr_ty())
);
p!(" upvar_tys=(");
self.comma_sep(args.as_closure().upvar_tys().iter())?;
p!(")");
}
p!(
" closure_kind_ty=",
print(args.as_closure().kind_ty()),
" closure_sig_as_fn_ptr_ty=",
print(args.as_closure().sig_as_fn_ptr_ty()),
" upvar_tys=",
print(args.as_closure().tupled_upvars_ty())
);
}
p!("}}");
}

View File

@ -242,9 +242,15 @@ pub struct ClosureArgs<'tcx> {
/// Struct returned by `split()`.
pub struct ClosureArgsParts<'tcx> {
/// This is the args of the typeck root.
pub parent_args: &'tcx [GenericArg<'tcx>],
/// Represents the maximum calling capability of the closure.
pub closure_kind_ty: Ty<'tcx>,
/// Captures the closure's signature. This closure signature is "tupled", and
/// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`.
pub closure_sig_as_fn_ptr_ty: Ty<'tcx>,
/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: Ty<'tcx>,
}
@ -277,15 +283,6 @@ fn split(self) -> ClosureArgsParts<'tcx> {
}
}
/// Returns `true` only if enough of the synthetic types are known to
/// allow using all of the methods on `ClosureArgs` without panicking.
///
/// Used primarily by `ty::print::pretty` to be able to handle closure
/// types that haven't had their synthetic types substituted in.
pub fn is_valid(self) -> bool {
self.args.len() >= 3 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_))
}
/// Returns the substitutions of the closure's parent.
pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
self.split().parent_args
@ -296,9 +293,9 @@ pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
/// empty iterator is returned.
#[inline]
pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
match self.tupled_upvars_ty().kind() {
match *self.tupled_upvars_ty().kind() {
TyKind::Error(_) => ty::List::empty(),
TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
TyKind::Tuple(tys) => tys,
TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
}
@ -337,10 +334,9 @@ pub fn kind(self) -> ty::ClosureKind {
/// Extracts the signature from the closure.
pub fn sig(self) -> ty::PolyFnSig<'tcx> {
let ty = self.sig_as_fn_ptr_ty();
match ty.kind() {
ty::FnPtr(sig) => *sig,
_ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
match *self.sig_as_fn_ptr_ty().kind() {
ty::FnPtr(sig) => sig,
ty => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"),
}
}
@ -356,11 +352,17 @@ pub struct CoroutineArgs<'tcx> {
}
pub struct CoroutineArgsParts<'tcx> {
/// This is the args of the typeck root.
pub parent_args: &'tcx [GenericArg<'tcx>],
pub resume_ty: Ty<'tcx>,
pub yield_ty: Ty<'tcx>,
pub return_ty: Ty<'tcx>,
/// The interior type of the coroutine.
/// Represents all types that are stored in locals
/// in the coroutine's body.
pub witness: Ty<'tcx>,
/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: Ty<'tcx>,
}
@ -397,15 +399,6 @@ fn split(self) -> CoroutineArgsParts<'tcx> {
}
}
/// Returns `true` only if enough of the synthetic types are known to
/// allow using all of the methods on `CoroutineArgs` without panicking.
///
/// Used primarily by `ty::print::pretty` to be able to handle coroutine
/// types that haven't had their synthetic types substituted in.
pub fn is_valid(self) -> bool {
self.args.len() >= 5 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_))
}
/// Returns the substitutions of the coroutine's parent.
pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
self.split().parent_args
@ -425,9 +418,9 @@ pub fn witness(self) -> Ty<'tcx> {
/// empty iterator is returned.
#[inline]
pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
match self.tupled_upvars_ty().kind() {
match *self.tupled_upvars_ty().kind() {
TyKind::Error(_) => ty::List::empty(),
TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
TyKind::Tuple(tys) => tys,
TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
}

View File

@ -1,7 +1,7 @@
//! Computes a normalizes-to (projection) goal for inherent associated types,
//! `#![feature(lazy_type_alias)]` and `#![feature(type_alias_impl_trait)]`.
//!
//! Since a weak alias is not ambiguous, this just computes the `type_of` of
//! Since a weak alias is never ambiguous, this just computes the `type_of` of
//! the alias and registers the where-clauses of the type alias.
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;

View File

@ -232,32 +232,12 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
Ok::<_, NoSolution>(())
})?,
ty::Closure(_, args) => {
if !args.as_closure().is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
tcx.dcx().span_delayed_bug(
span,
format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
);
return Err(NoSolution);
ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in args.as_closure().upvar_tys() {
dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
}
rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in args.as_closure().upvar_tys() {
dtorck_constraint_for_ty_inner(
tcx,
param_env,
span,
depth + 1,
ty,
constraints,
)?;
}
Ok::<_, NoSolution>(())
})?
}
Ok::<_, NoSolution>(())
})?,
ty::Coroutine(_, args) => {
// rust-lang/rust#49918: types can be constructed, stored
@ -283,15 +263,6 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// derived from lifetimes attached to the upvars and resume
// argument, and we *do* incorporate those here.
let args = args.as_coroutine();
if !args.is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
tcx.dcx().span_delayed_bug(
span,
format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",),
);
return Err(NoSolution);
}
// While we conservatively assume that all coroutines require drop
// to avoid query cycles during MIR building, we can check the actual

View File

@ -141,6 +141,13 @@ fn fully_perform(
infcx: &InferCtxt<'tcx>,
span: Span,
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
// In the new trait solver, query type ops are performed locally. This
// is because query type ops currently use the old canonicalizer, and
// that doesn't preserve things like opaques which have been registered
// during MIR typeck. Even after the old canonicalizer is gone, it's
// probably worthwhile just keeping this run-locally logic, since we
// probably don't gain much from caching here given the new solver does
// caching internally.
if infcx.next_trait_solver() {
return Ok(scrape_region_constraints(
infcx,

View File

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

View File

@ -9,7 +9,7 @@ LL | let c1 : () = c;
| expected due to this
|
= note: expected unit type `()`
found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
found closure `{f<T>::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}`
help: use parentheses to call this closure
|
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
|
= note: expected fn pointer `fn(u8) -> u8`
found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}`
found closure `{main::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn((u8,)) -> u8 upvar_tys=?4t}`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> $DIR/closure-print-verbose.rs:10:39
|

View File

@ -4,7 +4,7 @@ error: coroutine cannot be shared between threads safely
LL | assert_sync(|| {
| ^^^^^^^^^^^ coroutine is not `Sync`
|
= help: within `{main::{closure#0} upvar_tys=() {main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
= help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
note: coroutine is not `Sync` as this value is used across a yield
--> $DIR/coroutine-print-verbose-2.rs:20:9
|
@ -24,7 +24,7 @@ error: coroutine cannot be sent between threads safely
LL | assert_send(|| {
| ^^^^^^^^^^^ coroutine is not `Send`
|
= help: within `{main::{closure#1} upvar_tys=() {main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
= help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
note: coroutine is not `Send` as this value is used across a yield
--> $DIR/coroutine-print-verbose-2.rs:27:9
|

View File

@ -12,7 +12,7 @@ LL | | };
| |_____^ expected `()`, found coroutine
|
= note: expected unit type `()`
found coroutine `{main::{closure#0} upvar_tys=(unavailable)}`
found coroutine `{main::{closure#0} upvar_tys=?4t witness=?6t}`
error: aborting due to 1 previous error