From c1b4824800597f7ce9831ae27dc994badabc40e3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 19 Nov 2020 18:24:03 -0500 Subject: [PATCH 1/8] factor fallback code into its own module --- compiler/rustc_typeck/src/check/fallback.rs | 52 +++++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 46 +----------------- 2 files changed, 54 insertions(+), 44 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/fallback.rs diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs new file mode 100644 index 0000000000000..5d884f1f54691 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -0,0 +1,52 @@ +use crate::check::FallbackMode; +use crate::check::FnCtxt; + +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, 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. + 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_if_possible(ty, FallbackMode::All); + } + + // See if we can make any more progress. + self.select_obligations_where_possible(fallback_has_occurred, |_| {}); + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index d1e583ed1845a..9c6a441d01abf 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -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. From 7e0ae7d89bcbf5174ab2d5198c438cfd0bebd4e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 20 Nov 2020 05:40:33 -0500 Subject: [PATCH 2/8] introduce a `Diverging` enum instead of a bool --- compiler/rustc_infer/src/infer/combine.rs | 6 +- compiler/rustc_infer/src/infer/mod.rs | 20 ++-- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +- .../rustc_infer/src/infer/type_variable.rs | 12 ++- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 97 ++++++++++--------- 5 files changed, 78 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 3a11b5a214490..79dc1c4bee63a 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -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,7 +643,7 @@ 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); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); Ok(u) @@ -881,7 +881,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); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9b9ded5c6bab4..26bee3596e3dd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -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,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { + 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, } } @@ -1020,12 +1020,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 +1033,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 +1156,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, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 20be06adfd09e..261c3471a9829 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -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); diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 13b78b26af424..42e2a0c858698 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -119,7 +119,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 +179,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 +244,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 }); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index c13901ae8be2b..9405b64260c4d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, Node, QPath, TyKind}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::type_variable::Diverging; use rustc_infer::infer::{InferOk, InferResult}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; @@ -656,56 +657,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ 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 { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option` 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 + Neither => match self.type_var_diverges(ty) { + Diverging::Diverges => self.tcx.mk_diverging_default(), + + Diverging::NotDiverging => { + // 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 { + // None + // } + // ``` + // + // In the above snippet, the inference variable created by + // instantiating `Option` 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; } - } else { - return false; } - } + }, }; debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); From 5eca626e4025fc4f4695aeba03cd60b344001378 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 20 Nov 2020 05:52:27 -0500 Subject: [PATCH 3/8] shallow resolve target type in coercion We used to avoid doing this because we didn't want to make coercion depend on the state of inference. For better or worse, we have moved away from this position over time. Therefore, I am going to go ahead and resolve the `b` target type early on so that it is done uniformly. (The older technique for managing this was always something of a hack regardless; if we really wanted to avoid integrating coercion and inference we needed to be more disciplined about it.) --- compiler/rustc_typeck/src/check/coercion.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 208eb27c84406..0f39d2819ab4e 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -147,6 +147,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { let a = self.shallow_resolve(a); + let b = self.shallow_resolve(b); debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. @@ -162,8 +163,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // let _: Option = 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 { @@ -196,9 +196,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); From 5a8edc0b7607b997dd926b5d882cd39000386cdc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 21 Nov 2020 05:45:13 -0500 Subject: [PATCH 4/8] cleanup: extract a helper for coercion from inference variables --- compiler/rustc_typeck/src/check/coercion.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 0f39d2819ab4e..7e03ef1814402 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -146,6 +146,7 @@ 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); @@ -155,6 +156,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 @@ -176,6 +178,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; } + // 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); + } + // Consider coercing the subtype to a DST // // NOTE: this is wrapped in a `commit_if_ok` because it creates @@ -233,6 +242,16 @@ 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>) -> CoerceResult<'tcx> { + assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a); + assert!(self.infcx.shallow_resolve(b) == b); + + self.unify_and(a, b, identity) + } + /// 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. From 947c0de028a01be4edd9c10173956c32226595c2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 21 Nov 2020 07:06:16 -0500 Subject: [PATCH 5/8] introduce a Coerce predicate --- compiler/rustc_infer/src/infer/mod.rs | 29 +++++++++++++++++++ .../rustc_infer/src/infer/outlives/mod.rs | 1 + compiler/rustc_infer/src/traits/util.rs | 4 +++ compiler/rustc_lint/src/builtin.rs | 1 + compiler/rustc_middle/src/ty/flags.rs | 4 +++ compiler/rustc_middle/src/ty/mod.rs | 28 ++++++++++++++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 5 ++++ .../rustc_middle/src/ty/structural_impls.rs | 9 ++++++ .../src/transform/check_consts/check.rs | 4 +-- .../rustc_trait_selection/src/opaque_types.rs | 1 + .../src/traits/error_reporting/mod.rs | 7 +++++ .../src/traits/fulfill.rs | 26 +++++++++++++++++ .../src/traits/object_safety.rs | 2 ++ .../src/traits/select/mod.rs | 16 ++++++++++ .../rustc_trait_selection/src/traits/wf.rs | 4 +++ compiler/rustc_traits/src/chalk/lowering.rs | 4 +++ .../src/implied_outlives_bounds.rs | 1 + .../src/normalize_erasing_regions.rs | 1 + .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 1 + .../rustc_typeck/src/check/method/probe.rs | 1 + .../src/impl_wf_check/min_specialization.rs | 1 + .../rustc_typeck/src/outlives/explicit.rs | 1 + src/librustdoc/clean/mod.rs | 1 + .../clippy_utils/src/qualify_min_const_fn.rs | 3 ++ 24 files changed, 153 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 26bee3596e3dd..172eb1f48d7c2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -969,6 +969,35 @@ 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> { + 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>, diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 07c75d50d91da..4dd5e8ba54500 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -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(..) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 3139e12116373..3a25cb66896d5 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -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. } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 77c7040e6a76d..5a72db7752d63 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1652,6 +1652,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ObjectSafe(..) | ClosureKind(..) | Subtype(..) | + Coerce(..) | ConstEvaluatable(..) | ConstEquate(..) | TypeWellFormedFromEnv(..) => continue, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 391c8292bd542..04df706d90842 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -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); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0906cffa05c32..9fcf35b732077 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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, SubstsRef<'tcx>), @@ -655,6 +669,9 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, 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(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c96621338f574..8558d6bb00e72 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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)), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 62397752db2fc..a46cac1e7f7f5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -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> { + 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 { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -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) } diff --git a/compiler/rustc_mir/src/transform/check_consts/check.rs b/compiler/rustc_mir/src/transform/check_consts/check.rs index 48fd63b258ca7..09e908e675731 100644 --- a/compiler/rustc_mir/src/transform/check_consts/check.rs +++ b/compiler/rustc_mir/src/transform/check_consts/check.rs @@ -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() { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 1a195ce18ec64..e6686b8cc7070 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -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(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 2f91666ca641d..2c09c551b656f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 7048f0dbedcb6..a2095907c7a2d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -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(), diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 04bc689d51161..02b43de0d1606 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -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(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 38dbacbf2ae6c..c9bcc44fab634 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -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, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9c9664d7b5e84..afef784b4c6cc 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -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); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 974755e9e2669..330fd497fa1f8 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -109,6 +109,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment bug!("unexpected predicate {}", predicate), }; @@ -193,6 +194,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> 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 { @@ -719,6 +722,7 @@ impl<'tcx> LowerInto<'tcx, Option { diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 90ba90259c32b..1d10d06849062 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -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(..) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 5ad0684fe6ee2..61ab5e28b6796 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -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, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 9405b64260c4d..a9b1fb790edee 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -812,6 +812,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, diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index c6e6c8c5d70e2..486e4d15d6580 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -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(..) diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index d5d81603fc516..e148370a03610 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -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(..) diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index 6e5be87928d59..2ac1a18cffaf1 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -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(..) => (), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 73b5ef0857d4f..b6ff3890c584e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -332,6 +332,7 @@ impl<'a> Clean> for ty::Predicate<'a> { ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index dee9d487c78ea..8e544f580665e 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -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; From 020655b90da83b0a037a9d3c987be17f04eedbc4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 21 Nov 2020 15:33:36 -0500 Subject: [PATCH 6/8] move the `sub-unify` check and extend the documentation a bit I didn't like the sub-unify code executing when a predicate was ENQUEUED, that felt fragile. I would have preferred to move the sub-unify code so that it only occurred during generalization, but that impacted diagnostics, so having it also occur when we process subtype predicates felt pretty reasonable. (I guess we only need one or the other, but I kind of prefer both, since the generalizer ultimately feels like the *right* place to guarantee the properties we want.) --- compiler/rustc_infer/src/infer/combine.rs | 5 +++ compiler/rustc_infer/src/infer/mod.rs | 34 +++++++++++-------- compiler/rustc_infer/src/infer/sub.rs | 8 ++--- .../rustc_infer/src/infer/type_variable.rs | 24 ++++++++++--- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 79dc1c4bee63a..01d84e287bc9f 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -645,6 +645,11 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .type_variables() .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) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 172eb1f48d7c2..b3d6e44d80eb6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1004,23 +1004,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, predicate: ty::PolySubtypePredicate<'tcx>, ) -> Option> { - // 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| { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 2f126d8956905..1692d8ee526d0 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -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, diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 42e2a0c858698..d2b0bdaf97802 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -75,14 +75,30 @@ pub struct TypeVariableStorage<'tcx> { /// ?1 <: ?3 /// Box <: ?1 /// - /// This works because `?1` and `?3` are unified in the - /// `sub_relations` relation (not in `eq_relations`). Then when we - /// process the `Box <: ?1` constraint, we do an occurs check - /// on `Box` 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`. We would then relate `Box <: Box` + /// and infer that `?3 <: ?6`. Next, since `?1` was instantiated, + /// we would process `?1 <: ?3`, generalize `?1 = Box` to `Box`, + /// and instantiate `?3` with `Box`. Finally, we would relate + /// `?6 <: ?9`. But now that we instantiated `?3`, we can process + /// `?3 <: ?6`, which gives us `Box <: ?6`... and the cycle + /// continues. (This is `occurs-check-2.rs`.) + /// + /// What prevents this cycle is that when we generalize + /// `Box` to `Box`, we also sub-unify `?3` and `?6` + /// (in the generalizer). When we then process `Box <: ?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` 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, } From faf84263f2acd638801069beea0d4b9dd662c111 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 21 Nov 2020 15:47:14 -0500 Subject: [PATCH 7/8] create `Coercion` obligations given 2 unbound type variables Motivation: in upcoming commits, we are going to create a graph of the coercion relationships between variables. We want to distinguish *coercion* specifically from other sorts of subtyping, as it indicates values flowing from one place to another via assignment. --- compiler/rustc_typeck/src/check/coercion.rs | 53 +++++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 7e03ef1814402..0b4df8e6d3cdd 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -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}; @@ -172,7 +173,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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![]) }; @@ -182,7 +183,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // 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); + return self.coerce_from_inference_variable(a, b, identity); } // Consider coercing the subtype to a DST @@ -245,11 +246,53 @@ 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>) -> CoerceResult<'tcx> { + fn coerce_from_inference_variable( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec>, + ) -> 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); - self.unify_and(a, b, identity) + 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`. From 60cc00f540658cb82bccf88275f9cf409215a6b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Nov 2020 06:10:50 -0500 Subject: [PATCH 8/8] move `fallback_if_possible` and friends to fallback.rs Along the way, simplify and document the logic more clearly. --- compiler/rustc_infer/src/infer/mod.rs | 41 +++---- compiler/rustc_middle/src/ty/error.rs | 6 - compiler/rustc_typeck/src/check/fallback.rs | 111 +++++++++++++++++- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 84 +------------ compiler/rustc_typeck/src/check/mod.rs | 10 -- 5 files changed, 127 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b3d6e44d80eb6..80f1a0d325466 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -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}; @@ -679,6 +679,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } + /// 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), @@ -686,6 +690,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// 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 { + match *ty.kind() { + ty::Infer(ty::TyVar(vid)) => { + Some(*self.inner.borrow_mut().type_variables().var_origin(vid)) + } + _ => None, + } + } + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { freshen::TypeFreshener::new(self, false) } @@ -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> { let mut inner = self.inner.borrow_mut(); let mut vars: Vec> = inner diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 3846d9ffdbae5..1aa6c84dbc414 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -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 diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 5d884f1f54691..69a8970ae094e 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,5 +1,6 @@ -use crate::check::FallbackMode; 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) { @@ -12,8 +13,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // 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, FallbackMode::NoOpaque); + 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 @@ -43,10 +45,113 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // unconstrained opaque type variables, in addition to performing // other kinds of fallback. for ty in &self.unsolved_variables() { - fallback_has_occurred |= self.fallback_if_possible(ty, FallbackMode::All); + 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 { + /// None + /// } + /// ``` + /// + /// In the above snippet, the inference variable created by + /// instantiating `Option` 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; + } + } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index a9b1fb790edee..bb80f0879a4aa 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -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; @@ -17,7 +17,6 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, Node, QPath, TyKind}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::type_variable::Diverging; use rustc_infer::infer::{InferOk, InferResult}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; @@ -636,87 +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 => match self.type_var_diverges(ty) { - Diverging::Diverges => self.tcx.mk_diverging_default(), - - Diverging::NotDiverging => { - // 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 { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option` 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 diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 9c6a441d01abf..ad7e96e2833b8 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -872,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> {