pub mod dropck;
mod expectation;
mod expr;
+mod fallback;
mod fn_ctxt;
mod gather_locals;
mod generator_interior;
fn_sig,
);
- let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
+ let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
fcx
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
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, |_| {});
+ let 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.
fcx.check_casts();
+ fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate, _) => {
+ ty::PredicateKind::Trait(trait_predicate) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
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> {