diff options
Diffstat (limited to 'compiler/rustc_infer/src/infer/sub.rs')
-rw-r--r-- | compiler/rustc_infer/src/infer/sub.rs | 61 |
1 files changed, 28 insertions, 33 deletions
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index b7eab5d43..97354ba5d 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -2,9 +2,7 @@ use super::combine::{CombineFields, RelationDir}; use super::SubregionOrigin; use crate::infer::combine::ConstEquateRelation; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::Obligation; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::TyVar; @@ -12,8 +10,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, +pub struct Sub<'combine, 'a, 'tcx> { + fields: &'combine mut CombineFields<'a, 'tcx>, a_is_expected: bool, } @@ -130,39 +128,36 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if self.fields.define_opaque_types && did.is_local() => { - let mut generalize = |ty, ty_is_expected| { - let var = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.fields.trace.cause.span, - }, - ty::UniverseIndex::ROOT, - ); - self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?; - Ok(infcx.tcx.mk_ty_var(var)) - }; - let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) }; - let (ga, gb) = match (a.kind(), b.kind()) { - (&ty::Opaque(..), _) => (a, generalize(b, true)?), - (_, &ty::Opaque(..)) => (generalize(a, false)?, b), - _ => unreachable!(), - }; self.fields.obligations.extend( infcx - .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env()) - // Don't leak any generalized type variables out of this - // subtyping relation in the case of a type error. - .map_err(|err| { - let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb)); - if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb { - TypeError::Sorts(ExpectedFound { expected: a, found: b }) - } else { - err - } - })? + .handle_opaque_type( + a, + b, + self.a_is_expected, + &self.fields.trace.cause, + self.param_env(), + )? .obligations, ); - Ok(ga) + Ok(a) + } + // Optimization of GeneratorWitness relation since we know that all + // free regions are replaced with bound regions during construction. + // This greatly speeds up subtyping of GeneratorWitness. + (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { + let a_types = infcx.tcx.anonymize_bound_vars(a_types); + let b_types = infcx.tcx.anonymize_bound_vars(b_types); + if a_types.bound_vars() == b_types.bound_vars() { + let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders( + a_types.map_bound(|a_types| (a_types, b_types.skip_binder())), + ); + for (a, b) in std::iter::zip(a_types, b_types) { + self.relate(a, b)?; + } + Ok(a) + } else { + Err(ty::error::TypeError::Sorts(ty::relate::expected_found(self, a, b))) + } } _ => { |