Auto merge of #88149 - Mark-Simulacrum:prep-never-type, r=jackh726

Refactor fallback code to prepare for never type

This PR contains cherry-picks of some of `@nikomatsakis's` work from #79366, and shouldn't (AFAICT) represent any change in behavior. However, the refactoring is good regardless of the never type work being landed, and will reduce the size of those eventual PR(s) (and rebase pain).

I am not personally an expert on this code, and the commits are essentially 100% `@nikomatsakis's,` but they do seem reasonable to me by my understanding. Happy to edit with review, of course. Commits are best reviewed in sequence rather than all together.

r? `@jackh726` perhaps?
This commit is contained in:
bors 2021-08-21 01:29:12 +00:00
commit 797095a686
32 changed files with 470 additions and 210 deletions

View File

@ -22,7 +22,6 @@
// is also useful to track which value is the "expected" value in
// terms of error reporting.
use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
@ -30,6 +29,7 @@ use super::type_variable::TypeVariableValue;
use super::unify_key::replace_if_possible;
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use super::{equate::Equate, type_variable::Diverging};
use super::{InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
@ -643,8 +643,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
.inner
.borrow_mut()
.type_variables()
.new_var(self.for_universe, false, origin);
.new_var(self.for_universe, Diverging::NotDiverging, origin);
let u = self.tcx().mk_ty_var(new_var_id);
// Record that we replaced `vid` with `new_var_id` as part of a generalization
// operation. This is needed to detect cyclic types. To see why, see the
// docs in the `type_variables` module.
self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
Ok(u)
}
@ -881,7 +886,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
self.for_universe,
false,
Diverging::NotDiverging,
origin,
);
let u = self.tcx().mk_ty_var(new_var_id);

View File

@ -23,7 +23,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
pub mod at;
pub mod canonical;
@ -679,10 +679,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
t.fold_with(&mut self.freshener())
}
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
/// Returns whether `ty` is a diverging type variable or not.
/// (If `ty` is not a type variable at all, returns not diverging.)
///
/// No attempt is made to resolve `ty`.
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
_ => false,
_ => Diverging::NotDiverging,
}
}
/// Returns the origin of the type variable identified by `vid`, or `None`
/// if this is not a type variable.
///
/// No attempt is made to resolve `ty`.
pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => {
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
}
_ => None,
}
}
@ -695,28 +712,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
freshen::TypeFreshener::new(self, true)
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
match *ty.kind() {
ty::Infer(ty::IntVar(vid)) => {
if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
Neither
} else {
UnconstrainedInt
}
}
ty::Infer(ty::FloatVar(vid)) => {
if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
Neither
} else {
UnconstrainedFloat
}
}
_ => Neither,
}
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut inner = self.inner.borrow_mut();
let mut vars: Vec<Ty<'_>> = inner
@ -969,29 +964,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
/// Processes a `Coerce` predicate from the fulfillment context.
/// This is NOT the preferred way to handle coercion, which is to
/// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
///
/// This method here is actually a fallback that winds up being
/// invoked when `FnCtxt::coerce` encounters unresolved type variables
/// and records a coercion predicate. Presently, this method is equivalent
/// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up
/// actually requiring `a <: b`. This is of course a valid coercion,
/// but it's not as flexible as `FnCtxt::coerce` would be.
///
/// (We may refactor this in the future, but there are a number of
/// practical obstacles. Among other things, `FnCtxt::coerce` presently
/// records adjustments that are required on the HIR in order to perform
/// the coercion, and we don't currently have a way to manage that.)
pub fn coerce_predicate(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolyCoercePredicate<'tcx>,
) -> Option<InferResult<'tcx, ()>> {
let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
a: p.a,
b: p.b,
});
self.subtype_predicate(cause, param_env, subtype_predicate)
}
pub fn subtype_predicate(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolySubtypePredicate<'tcx>,
) -> Option<InferResult<'tcx, ()>> {
// Subtle: it's ok to skip the binder here and resolve because
// `shallow_resolve` just ignores anything that is not a type
// variable, and because type variable's can't (at present, at
// Check for two unresolved inference variables, in which case we can
// make no progress. This is partly a micro-optimization, but it's
// also an opportunity to "sub-unify" the variables. This isn't
// *necessary* to prevent cycles, because they would eventually be sub-unified
// anyhow during generalization, but it helps with diagnostics (we can detect
// earlier that they are sub-unified).
//
// Note that we can just skip the binders here because
// type variables can't (at present, at
// least) capture any of the things bound by this binder.
//
// NOTE(nmatsakis): really, there is no *particular* reason to do this
// `shallow_resolve` here except as a micro-optimization.
// Naturally I could not resist.
let two_unbound_type_vars = {
let a = self.shallow_resolve(predicate.skip_binder().a);
let b = self.shallow_resolve(predicate.skip_binder().b);
a.is_ty_var() && b.is_ty_var()
};
if two_unbound_type_vars {
// Two unbound type variables? Can't make progress.
return None;
// Note that this sub here is not just for diagnostics - it has semantic
// effects as well.
let r_a = self.shallow_resolve(predicate.skip_binder().a);
let r_b = self.shallow_resolve(predicate.skip_binder().b);
match (r_a.kind(), r_b.kind()) {
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
return None;
}
_ => {}
}
Some(self.commit_if_ok(|_snapshot| {
@ -1020,12 +1048,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
})
}
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
}
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
}
pub fn next_ty_var_in_universe(
@ -1033,12 +1061,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> Ty<'tcx> {
let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
let vid = self.inner.borrow_mut().type_variables().new_var(
universe,
Diverging::NotDiverging,
origin,
);
self.tcx.mk_ty_var(vid)
}
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
}
pub fn next_const_var(
@ -1152,7 +1184,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// as the substitutions for the default, `(T, U)`.
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
self.universe(),
false,
Diverging::NotDiverging,
TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(
param.name,

View File

@ -22,6 +22,7 @@
//! constituents)
use crate::infer::combine::ConstEquateRelation;
use crate::infer::type_variable::Diverging;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use rustc_data_structures::fx::FxHashMap;
@ -920,7 +921,8 @@ where
// Replacing with a new variable in the universe `self.universe`,
// it will be unified later with the original type variable in
// the universe `_universe`.
let new_var_id = variables.new_var(self.universe, false, origin);
let new_var_id =
variables.new_var(self.universe, Diverging::NotDiverging, origin);
let u = self.tcx().mk_ty_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);

View File

@ -19,6 +19,7 @@ pub fn explicit_outlives_bounds<'tcx>(
.filter_map(move |kind| match kind {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)

View File

@ -85,7 +85,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put
// this under a binder below without fear of accidental
// capture.
@ -93,11 +93,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
assert!(!b.has_escaping_bound_vars());
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation. We also
// have to record in the `type_variables` tracker that
// the two variables are equal modulo subtyping, which
// is important to the occurs check later on.
infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
// type variables, so record an obligation.
self.fields.obligations.push(Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,

View File

@ -75,14 +75,30 @@ pub struct TypeVariableStorage<'tcx> {
/// ?1 <: ?3
/// Box<?3> <: ?1
///
/// This works because `?1` and `?3` are unified in the
/// `sub_relations` relation (not in `eq_relations`). Then when we
/// process the `Box<?3> <: ?1` constraint, we do an occurs check
/// on `Box<?3>` and find a potential cycle.
/// Without this second table, what would happen in a case like
/// this is that we would instantiate `?1` with a generalized
/// type like `Box<?6>`. We would then relate `Box<?3> <: Box<?6>`
/// and infer that `?3 <: ?6`. Next, since `?1` was instantiated,
/// we would process `?1 <: ?3`, generalize `?1 = Box<?6>` to `Box<?9>`,
/// and instantiate `?3` with `Box<?9>`. Finally, we would relate
/// `?6 <: ?9`. But now that we instantiated `?3`, we can process
/// `?3 <: ?6`, which gives us `Box<?9> <: ?6`... and the cycle
/// continues. (This is `occurs-check-2.rs`.)
///
/// What prevents this cycle is that when we generalize
/// `Box<?3>` to `Box<?6>`, we also sub-unify `?3` and `?6`
/// (in the generalizer). When we then process `Box<?6> <: ?3`,
/// the occurs check then fails because `?6` and `?3` are sub-unified,
/// and hence generalization fails.
///
/// This is reasonable because, in Rust, subtypes have the same
/// "skeleton" and hence there is no possible type such that
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
///
/// In practice, we sometimes sub-unify variables in other spots, such
/// as when processing subtype predicates. This is not necessary but is
/// done to aid diagnostics, as it allows us to be more effective when
/// we guide the user towards where they should insert type hints.
sub_relations: ut::UnificationTableStorage<ty::TyVid>,
}
@ -119,7 +135,13 @@ pub enum TypeVariableOriginKind {
pub(crate) struct TypeVariableData {
origin: TypeVariableOrigin,
diverging: bool,
diverging: Diverging,
}
#[derive(Copy, Clone, Debug)]
pub enum Diverging {
NotDiverging,
Diverges,
}
#[derive(Copy, Clone, Debug)]
@ -173,7 +195,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
///
/// Note that this function does not return care whether
/// `vid` has been unified with something else or not.
pub fn var_diverges(&self, vid: ty::TyVid) -> bool {
pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
self.storage.values.get(vid.index as usize).diverging
}
@ -238,7 +260,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
pub fn new_var(
&mut self,
universe: ty::UniverseIndex,
diverging: bool,
diverging: Diverging,
origin: TypeVariableOrigin,
) -> ty::TyVid {
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });

View File

@ -158,6 +158,10 @@ impl Elaborator<'tcx> {
// Currently, we do not "elaborate" predicates like `X <: Y`,
// though conceivably we might.
}
ty::PredicateKind::Coerce(..) => {
// Currently, we do not "elaborate" predicates like `X -> Y`,
// though conceivably we might.
}
ty::PredicateKind::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}

View File

@ -1652,6 +1652,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
Coerce(..) |
ConstEvaluatable(..) |
ConstEquate(..) |
TypeWellFormedFromEnv(..) => continue,

View File

@ -71,12 +71,6 @@ pub enum TypeError<'tcx> {
TargetFeatureCast(DefId),
}
pub enum UnconstrainedNumeric {
UnconstrainedFloat,
UnconstrainedInt,
Neither,
}
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related

View File

@ -231,6 +231,10 @@ impl FlagComputation {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
self.add_projection_ty(projection_ty);
self.add_ty(ty);

View File

@ -485,8 +485,22 @@ pub enum PredicateKind<'tcx> {
ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
/// `T1 <: T2`
///
/// This obligation is created most often when we have two
/// unresolved type variables and hence don't have enough
/// information to process the subtyping obligation yet.
Subtype(SubtypePredicate<'tcx>),
/// `T1` coerced to `T2`
///
/// Like a subtyping obligation, this is created most often
/// when we have two unresolved type variables and hence
/// don't have enough information to process the coercion
/// obligation yet. At the moment, we actually process coercions
/// very much like subtyping and don't handle the full coercion
/// logic.
Coerce(CoercePredicate<'tcx>),
/// Constant initializer must evaluate successfully.
ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
@ -655,6 +669,9 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'t
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
/// whether the `a` type is the type that we should label as "expected" when
/// presenting user diagnostics.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct SubtypePredicate<'tcx> {
@ -664,6 +681,15 @@ pub struct SubtypePredicate<'tcx> {
}
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
/// Encodes that we have to coerce *from* the `a` type to the `b` type.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct CoercePredicate<'tcx> {
pub a: Ty<'tcx>,
pub b: Ty<'tcx>,
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@ -806,6 +832,7 @@ impl<'tcx> Predicate<'tcx> {
}
PredicateKind::Projection(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
| PredicateKind::RegionOutlives(..)
| PredicateKind::WellFormed(..)
| PredicateKind::ObjectSafe(..)
@ -824,6 +851,7 @@ impl<'tcx> Predicate<'tcx> {
PredicateKind::Trait(..)
| PredicateKind::Projection(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
| PredicateKind::RegionOutlives(..)
| PredicateKind::WellFormed(..)
| PredicateKind::ObjectSafe(..)

View File

@ -2236,6 +2236,10 @@ define_print_and_forward_display! {
p!(print(self.a), " <: ", print(self.b))
}
ty::CoercePredicate<'tcx> {
p!(print(self.a), " -> ", print(self.b))
}
ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": ",
print(self.trait_ref.print_only_trait_path()))
@ -2268,6 +2272,7 @@ define_print_and_forward_display! {
p!(print(data))
}
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
ty::PredicateKind::Projection(predicate) => p!(print(predicate)),

View File

@ -179,6 +179,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
match *self {
ty::PredicateKind::Trait(ref a) => a.fmt(f),
ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
@ -380,6 +381,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
type Lifted = ty::CoercePredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b })
}
}
impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@ -420,6 +428,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
match self {
ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
ty::PredicateKind::RegionOutlives(data) => {
tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
}

View File

@ -420,8 +420,8 @@ impl Checker<'mir, 'tcx> {
ty::PredicateKind::ClosureKind(..) => {
bug!("closure kind predicate on function: {:#?}", predicate)
}
ty::PredicateKind::Subtype(_) => {
bug!("subtype predicate on function: {:#?}", predicate)
ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
bug!("subtype/coerce predicate on function: {:#?}", predicate)
}
ty::PredicateKind::Trait(pred) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {

View File

@ -1119,6 +1119,7 @@ crate fn required_region_bounds(
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)

View File

@ -565,6 +565,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
}
ty::PredicateKind::Coerce(predicate) => {
// Errors for Coerce predicates show up as
// `FulfillmentErrorCode::CodeSubtypeError`,
// not selection error.
span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
}
ty::PredicateKind::RegionOutlives(predicate) => {
let predicate = bound_predicate.rebind(predicate);
let predicate = self.resolve_vars_if_possible(predicate);

View File

@ -402,6 +402,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
let pred = infcx.replace_bound_vars_with_placeholders(binder);
@ -517,6 +518,31 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
}
}
ty::PredicateKind::Coerce(coerce) => {
match self.selcx.infcx().coerce_predicate(
&obligation.cause,
obligation.param_env,
Binder::dummy(coerce),
) {
None => {
// None means that both are unresolved.
pending_obligation.stalled_on = vec![
TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(),
TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(),
];
ProcessResult::Unchanged
}
Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
Some(Err(err)) => {
let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
expected_found,
err,
))
}
}
}
ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
match const_evaluatable::is_const_evaluatable(
self.selcx.infcx(),

View File

@ -308,6 +308,7 @@ fn predicate_references_self(
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
@ -336,6 +337,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)

View File

@ -512,6 +512,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
ty::PredicateKind::Coerce(p) => {
let p = bound_predicate.rebind(p);
// Does this code ever run?
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
Some(Ok(InferOk { mut obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
}
Some(Err(_)) => Ok(EvaluatedToErr),
None => Ok(EvaluatedToAmbig),
}
}
ty::PredicateKind::WellFormed(arg) => match wf::obligations(
self.infcx,
obligation.param_env,

View File

@ -128,6 +128,10 @@ pub fn predicate_obligations<'a, 'tcx>(
wf.compute(a.into());
wf.compute(b.into());
}
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
wf.compute(a.into());
wf.compute(b.into());
}
ty::PredicateKind::ConstEvaluatable(def, substs) => {
let obligations = wf.nominal_obligations(def.did, substs);
wf.out.extend(obligations);

View File

@ -109,6 +109,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
};
@ -193,6 +194,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
// some of these in terms of chalk operations.
ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
@ -592,6 +594,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@ -719,6 +722,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {

View File

@ -99,6 +99,7 @@ fn compute_implied_outlives_bounds<'tcx>(
Some(pred) => match pred {
ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ObjectSafe(..)

View File

@ -65,6 +65,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => true,

View File

@ -42,6 +42,7 @@ 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_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@ -50,7 +51,7 @@ use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TypeAndMut};
use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, Span};
@ -146,7 +147,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
// First, remove any resolved type variables (at the top level, at least):
let a = self.shallow_resolve(a);
let b = self.shallow_resolve(b);
debug!("Coerce.tys({:?} => {:?})", a, b);
// Just ignore error types.
@ -154,6 +157,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}
// Coercing from `!` to any type is allowed:
if a.is_never() {
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
// type variable, we want `?T` to fallback to `!` if not
@ -162,20 +166,26 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// let _: Option<?T> = Some({ return; });
//
// here, we would coerce from `!` to `?T`.
let b = self.shallow_resolve(b);
return if self.shallow_resolve(b).is_ty_var() {
return if b.is_ty_var() {
// Micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: self.cause.span,
});
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
} else {
success(simple(Adjust::NeverToAny)(b), b, vec![])
};
}
// Coercing *from* an unresolved inference variable means that
// we have no information about the source type. This will always
// ultimately fall back to some form of subtyping.
if a.is_ty_var() {
return self.coerce_from_inference_variable(a, b, identity);
}
// Consider coercing the subtype to a DST
//
// NOTE: this is wrapped in a `commit_if_ok` because it creates
@ -196,9 +206,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
//
// Note: does not attempt to resolve type variables we encounter.
// See above for details.
match *b.kind() {
ty::RawPtr(mt_b) => {
return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
@ -236,6 +243,58 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
}
/// Coercing *from* an inference variable. In this case, we have no information
/// about the source type, so we can't really do a true coercion and we always
/// fall back to subtyping (`unify_and`).
fn coerce_from_inference_variable(
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
assert!(self.infcx.shallow_resolve(b) == b);
if b.is_ty_var() {
// Two unresolved type variables: create a `Coerce` predicate.
let target_ty = if self.use_lub {
self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::LatticeVariable,
span: self.cause.span,
})
} else {
b
};
let mut obligations = Vec::with_capacity(2);
for &source_ty in &[a, b] {
if source_ty != target_ty {
obligations.push(Obligation::new(
self.cause.clone(),
self.param_env,
ty::PredicateKind::Coerce(ty::CoercePredicate {
a: source_ty,
b: target_ty,
})
.to_predicate(self.tcx()),
));
}
}
debug!(
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
target_ty, obligations
);
let adjustments = make_adjustments(target_ty);
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
} else {
// One unresolved type variable: just apply subtyping, we may be able
// to do something useful.
self.unify_and(a, b, make_adjustments)
}
}
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
/// To match `A` with `B`, autoderef will be performed,
/// calling `deref`/`deref_mut` where necessary.

View File

@ -0,0 +1,157 @@
use crate::check::FnCtxt;
use rustc_infer::infer::type_variable::Diverging;
use rustc_middle::ty::{self, Ty};
impl<'tcx> FnCtxt<'_, 'tcx> {
pub(super) fn type_inference_fallback(&self) {
// All type checking constraints were added, try to fallback unsolved variables.
self.select_obligations_where_possible(false, |_| {});
let mut fallback_has_occurred = false;
// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in &self.unsolved_variables() {
debug!("unsolved_variable = {:?}", ty);
fallback_has_occurred |= self.fallback_if_possible(ty);
}
// We now see if we can make progress. This might
// cause us to unify inference variables for opaque types,
// since we may have unified some other type variables
// during the first phase of fallback.
// This means that we only replace inference variables with their underlying
// opaque types as a last resort.
//
// In code like this:
//
// ```rust
// type MyType = impl Copy;
// fn produce() -> MyType { true }
// fn bad_produce() -> MyType { panic!() }
// ```
//
// we want to unify the opaque inference variable in `bad_produce`
// with the diverging fallback for `panic!` (e.g. `()` or `!`).
// This will produce a nice error message about conflicting concrete
// types for `MyType`.
//
// If we had tried to fallback the opaque inference variable to `MyType`,
// we will generate a confusing type-check error that does not explicitly
// refer to opaque types.
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
// We now run fallback again, but this time we allow it to replace
// unconstrained opaque type variables, in addition to performing
// other kinds of fallback.
for ty in &self.unsolved_variables() {
fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
}
// See if we can make any more progress.
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
//
// - Unconstrained ints are replaced with `i32`.
//
// - Unconstrained floats are replaced with with `f64`.
//
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
// is enabled. Otherwise, they are replaced with `()`.
//
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback based
// solely on how it was created, not what other type variables
// it may have been unified with since then.
//
// The reason this matters is that other attempts at fallback may
// (in principle) conflict with this fallback, and we wish to generate
// a type error in that case. (However, this actually isn't true right now,
// because we're only using the builtin fallback rules. This would be
// true if we were using user-supplied fallbacks. But it's still useful
// to write the code to detect bugs.)
//
// (Note though that if we have a general type variable `?T` that is then unified
// with an integer type variable `?I` that ultimately never gets
// resolved to a special integral type, `?T` is not considered unsolved,
// but `?I` is. The same is true for float variables.)
let fallback = match ty.kind() {
_ if self.is_tainted_by_errors() => self.tcx.ty_error(),
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match self.type_var_diverges(ty) {
Diverging::Diverges => self.tcx.mk_diverging_default(),
Diverging::NotDiverging => return false,
},
};
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
let span = self
.infcx
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
self.demand_eqtype(span, ty, fallback);
true
}
/// Second round of fallback: Unconstrained type variables
/// created from the instantiation of an opaque
/// type fall back to the opaque type itself. This is a
/// somewhat incomplete attempt to manage "identity passthrough"
/// for `impl Trait` types.
///
/// For example, in this code:
///
///```
/// type MyType = impl Copy;
/// fn defining_use() -> MyType { true }
/// fn other_use() -> MyType { defining_use() }
/// ```
///
/// `defining_use` will constrain the instantiated inference
/// variable to `bool`, while `other_use` will constrain
/// the instantiated inference variable to `MyType`.
///
/// When we process opaque types during writeback, we
/// will handle cases like `other_use`, and not count
/// them as defining usages
///
/// However, we also need to handle cases like this:
///
/// ```rust
/// pub type Foo = impl Copy;
/// fn produce() -> Option<Foo> {
/// None
/// }
/// ```
///
/// In the above snippet, the inference variable created by
/// instantiating `Option<Foo>` will be completely unconstrained.
/// We treat this as a non-defining use by making the inference
/// variable fall back to the opaque type itself.
fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
let span = self
.infcx
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
let oty = self.inner.borrow().opaque_types_vars.get(ty).map(|v| *v);
if let Some(opaque_ty) = oty {
debug!(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
ty, opaque_ty
);
self.demand_eqtype(span, ty, opaque_ty);
true
} else {
return false;
}
}
}

View File

@ -4,7 +4,7 @@ use crate::astconv::{
};
use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::captures::Captures;
@ -635,83 +635,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
//
// - Unconstrained ints are replaced with `i32`.
//
// - Unconstrained floats are replaced with with `f64`.
//
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
// is enabled. Otherwise, they are replaced with `()`.
//
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
assert!(ty.is_ty_infer());
let fallback = match self.type_is_unconstrained_numeric(ty) {
_ if self.is_tainted_by_errors() => self.tcx().ty_error(),
UnconstrainedInt => self.tcx.types.i32,
UnconstrainedFloat => self.tcx.types.f64,
Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
Neither => {
// This type variable was created from the instantiation of an opaque
// type. The fact that we're attempting to perform fallback for it
// means that the function neither constrained it to a concrete
// type, nor to the opaque type itself.
//
// For example, in this code:
//
//```
// type MyType = impl Copy;
// fn defining_use() -> MyType { true }
// fn other_use() -> MyType { defining_use() }
// ```
//
// `defining_use` will constrain the instantiated inference
// variable to `bool`, while `other_use` will constrain
// the instantiated inference variable to `MyType`.
//
// When we process opaque types during writeback, we
// will handle cases like `other_use`, and not count
// them as defining usages
//
// However, we also need to handle cases like this:
//
// ```rust
// pub type Foo = impl Copy;
// fn produce() -> Option<Foo> {
// None
// }
// ```
//
// In the above snippet, the inference variable created by
// instantiating `Option<Foo>` will be completely unconstrained.
// We treat this as a non-defining use by making the inference
// variable fall back to the opaque type itself.
if let FallbackMode::All = mode {
if let Some(opaque_ty) = self.infcx.inner.borrow().opaque_types_vars.get(ty) {
debug!(
"fallback_if_possible: falling back opaque type var {:?} to {:?}",
ty, opaque_ty
);
*opaque_ty
} else {
return false;
}
} else {
return false;
}
}
};
debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
true
}
pub(in super::super) fn select_all_obligations_or_error(&self) {
debug!("select_all_obligations_or_error");
if let Err(errors) = self
@ -807,6 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
}
ty::PredicateKind::Subtype(..) => None,
ty::PredicateKind::Coerce(..) => None,
ty::PredicateKind::RegionOutlives(..) => None,
ty::PredicateKind::TypeOutlives(..) => None,
ty::PredicateKind::WellFormed(..) => None,

View File

@ -841,6 +841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)

View File

@ -75,6 +75,7 @@ mod diverges;
pub mod dropck;
mod expectation;
mod expr;
mod fallback;
mod fn_ctxt;
mod gather_locals;
mod generator_interior;
@ -445,50 +446,7 @@ fn typeck_with_fallback<'tcx>(
fcx
};
// All type checking constraints were added, try to fallback unsolved variables.
fcx.select_obligations_where_possible(false, |_| {});
let mut fallback_has_occurred = false;
// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in &fcx.unsolved_variables() {
fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque);
}
// We now see if we can make progress. This might
// cause us to unify inference variables for opaque types,
// since we may have unified some other type variables
// during the first phase of fallback.
// This means that we only replace inference variables with their underlying
// opaque types as a last resort.
//
// In code like this:
//
// ```rust
// type MyType = impl Copy;
// fn produce() -> MyType { true }
// fn bad_produce() -> MyType { panic!() }
// ```
//
// we want to unify the opaque inference variable in `bad_produce`
// with the diverging fallback for `panic!` (e.g. `()` or `!`).
// This will produce a nice error message about conflicting concrete
// types for `MyType`.
//
// If we had tried to fallback the opaque inference variable to `MyType`,
// we will generate a confusing type-check error that does not explicitly
// refer to opaque types.
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
// We now run fallback again, but this time we allow it to replace
// unconstrained opaque type variables, in addition to performing
// other kinds of fallback.
for ty in &fcx.unsolved_variables() {
fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All);
}
// See if we can make any more progress.
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
@ -914,16 +872,6 @@ enum TupleArgumentsFlag {
TupleArguments,
}
/// Controls how we perform fallback for unconstrained
/// type variables.
enum FallbackMode {
/// Do not fallback type variables to opaque types.
NoOpaque,
/// Perform all possible kinds of fallback, including
/// turning type variables to opaque types.
All,
}
/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
#[derive(Copy, Clone)]
struct MaybeInProgressTables<'a, 'tcx> {

View File

@ -407,6 +407,7 @@ fn trait_predicate_kind<'tcx>(
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..)

View File

@ -56,6 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),

View File

@ -332,6 +332,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)

View File

@ -36,6 +36,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&Ru
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
ty::PredicateKind::Coerce(_) => {
panic!("coerce predicate on function: {:#?}", predicate)
},
ty::PredicateKind::Trait(pred) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;