Uplift TypeRelation and Relate
This commit is contained in:
parent
82ef3ad980
commit
91274c84b9
34 changed files with 1114 additions and 866 deletions
|
@ -4201,6 +4201,7 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_type_ir",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
@ -4508,6 +4509,7 @@ dependencies = [
|
|||
"rustc_serialize",
|
||||
"rustc_type_ir",
|
||||
"rustc_type_ir_macros",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
use std::ops::Index;
|
||||
|
@ -97,7 +97,7 @@ pub struct OutlivesConstraint<'tcx> {
|
|||
pub category: ConstraintCategory<'tcx>,
|
||||
|
||||
/// Variance diagnostic information
|
||||
pub variance_info: VarianceDiagInfo<'tcx>,
|
||||
pub variance_info: VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
|
||||
/// If this constraint is promoted from closure requirements.
|
||||
pub from_closure: bool,
|
||||
|
|
|
@ -2304,5 +2304,5 @@ pub struct BlameConstraint<'tcx> {
|
|||
pub category: ConstraintCategory<'tcx>,
|
||||
pub from_closure: bool,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::relate::{ObligationEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -82,7 +82,7 @@ pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
/// - Bivariant means that it doesn't matter.
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
||||
|
@ -296,7 +296,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
) {
|
||||
let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
|
||||
|
@ -314,7 +314,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.type_checker.infcx.tcx
|
||||
}
|
||||
|
@ -324,10 +324,10 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(skip(self, info), level = "trace", ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -445,7 +445,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
// We want that
|
||||
//
|
||||
|
|
|
@ -41,6 +41,7 @@ use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::infer::relate::RelateResult;
|
||||
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
|
||||
use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause};
|
||||
use rustc_infer::traits::{Obligation, PredicateObligation};
|
||||
|
@ -51,7 +52,6 @@ use rustc_middle::ty::adjustment::{
|
|||
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
|
||||
};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
|
|
@ -18,6 +18,7 @@ rustc_macros = { path = "../rustc_macros" }
|
|||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
use super::*;
|
||||
|
||||
use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::relate::{Relate, TypeRelation};
|
||||
use rustc_middle::ty::{Const, ImplSubject};
|
||||
|
||||
/// Whether we should define opaque types or just treat them opaquely.
|
||||
|
@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
||||
pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
|
||||
fn to_trace(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
|
|
|
@ -58,6 +58,7 @@ use crate::traits::{
|
|||
PredicateObligation,
|
||||
};
|
||||
|
||||
use crate::infer::relate::{self, RelateResult, TypeRelation};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString,
|
||||
|
@ -73,7 +74,6 @@ use rustc_middle::bug;
|
|||
use rustc_middle::dep_graph::DepContext;
|
||||
use rustc_middle::ty::error::TypeErrorToStringExt;
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
|
||||
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::Upcast;
|
||||
use rustc_middle::ty::{
|
||||
self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
|
||||
|
@ -2687,7 +2687,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
|
||||
/// FloatVar inference type are compatible with themselves or their concrete types (Int and
|
||||
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
|
||||
pub fn same_type_modulo_infer<T: relate::Relate<'tcx>>(&self, a: T, b: T) -> bool {
|
||||
pub fn same_type_modulo_infer<T: relate::Relate<TyCtxt<'tcx>>>(&self, a: T, b: T) -> bool {
|
||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||
SameTypeModuloInfer(self).relate(a, b).is_ok()
|
||||
}
|
||||
|
@ -2695,7 +2695,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.0.tcx
|
||||
}
|
||||
|
@ -2704,10 +2704,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
|||
"SameTypeModuloInfer"
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: relate::Relate<'tcx>>(
|
||||
fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
_variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> relate::RelateResult<'tcx, T> {
|
||||
|
@ -2755,7 +2755,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: relate::Relate<'tcx>,
|
||||
T: relate::Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
pub use at::DefineOpaqueTypes;
|
||||
pub use freshen::TypeFreshener;
|
||||
pub use lexical_region_resolve::RegionResolutionError;
|
||||
pub use relate::combine::CombineFields;
|
||||
pub use relate::combine::ObligationEmittingRelation;
|
||||
pub use relate::StructurallyRelateAliases;
|
||||
pub use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
pub use rustc_middle::ty::IntVarValue;
|
||||
pub use BoundRegionConversionTime::*;
|
||||
|
@ -11,6 +8,7 @@ pub use RegionVariableOrigin::*;
|
|||
pub use SubregionOrigin::*;
|
||||
pub use ValuePairs::*;
|
||||
|
||||
use crate::infer::relate::{CombineFields, RelateResult};
|
||||
use crate::traits::{
|
||||
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
|
||||
};
|
||||
|
@ -39,7 +37,6 @@ use rustc_middle::traits::select;
|
|||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fold::BoundVarReplacerDelegate;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
|
||||
|
@ -62,7 +59,7 @@ pub mod opaque_types;
|
|||
pub mod outlives;
|
||||
mod projection;
|
||||
pub mod region_constraints;
|
||||
mod relate;
|
||||
pub mod relate;
|
||||
pub mod resolve;
|
||||
pub(crate) mod snapshot;
|
||||
pub mod type_variable;
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
error::TypeError,
|
||||
relate::{self, Relate, RelateResult, TypeRelation},
|
||||
Ty, TyCtxt,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
use crate::infer::region_constraints::VerifyIfEq;
|
||||
use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation};
|
||||
|
||||
/// Given a "verify-if-eq" type test like:
|
||||
///
|
||||
|
@ -135,7 +132,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> {
|
||||
fn tag(&self) -> &'static str {
|
||||
"MatchAgainstHigherRankedOutlives"
|
||||
}
|
||||
|
@ -145,10 +142,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_: ty::VarianceDiagInfo<'tcx>,
|
||||
_: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -208,7 +205,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
value: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.pattern_depth.shift_in(1);
|
||||
let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::*;
|
||||
use crate::infer::relate::RelateResult;
|
||||
use crate::infer::snapshot::CombinedSnapshot;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph};
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
|
||||
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
/// Searches new universes created during `snapshot`, looking for
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::ty::error::TypeError;
|
||||
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use crate::ty::{self, InferConst, Ty, TyCtxt};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation};
|
||||
use crate::infer::relate;
|
||||
|
||||
/// A type "A" *matches* "B" if the fresh types in B could be
|
||||
/// instantiated with values so as to make it equal to A. Matching is
|
||||
/// intended to be used only on freshened types, and it basically
|
||||
|
@ -29,7 +31,7 @@ impl<'tcx> MatchAgainstFreshVars<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
|
||||
fn tag(&self) -> &'static str {
|
||||
"MatchAgainstFreshVars"
|
||||
}
|
||||
|
@ -38,10 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
_: ty::Variance,
|
||||
_: ty::VarianceDiagInfo<'tcx>,
|
||||
_: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -72,12 +74,12 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
) => Ok(a),
|
||||
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
Err(TypeError::Sorts(relate::expected_found(a, b)))
|
||||
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
||||
}
|
||||
|
||||
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)),
|
||||
|
||||
_ => relate::structurally_relate_tys(self, a, b),
|
||||
_ => structurally_relate_tys(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +99,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
}
|
||||
|
||||
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
|
||||
return Err(TypeError::ConstMismatch(relate::expected_found(a, b)));
|
||||
return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b)));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
@ -112,7 +114,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||
}
|
|
@ -22,12 +22,13 @@ use super::glb::Glb;
|
|||
use super::lub::Lub;
|
||||
use super::type_relating::TypeRelating;
|
||||
use super::StructurallyRelateAliases;
|
||||
use super::{RelateResult, TypeRelation};
|
||||
use crate::infer::relate;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::unify_key::EffectVarValue;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::Span;
|
||||
|
@ -121,7 +122,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::Yes => {
|
||||
ty::relate::structurally_relate_tys(relation, a, b)
|
||||
relate::structurally_relate_tys(relation, a, b)
|
||||
}
|
||||
StructurallyRelateAliases::No => {
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
|
@ -132,7 +133,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
// All other cases of inference are errors
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
Err(TypeError::Sorts(ty::relate::expected_found(a, b)))
|
||||
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
||||
}
|
||||
|
||||
// During coherence, opaque types should be treated as *possibly*
|
||||
|
@ -144,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ok(a)
|
||||
}
|
||||
|
||||
_ => ty::relate::structurally_relate_tys(relation, a, b),
|
||||
_ => relate::structurally_relate_tys(relation, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,11 +235,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ok(b)
|
||||
}
|
||||
StructurallyRelateAliases::Yes => {
|
||||
ty::relate::structurally_relate_consts(relation, a, b)
|
||||
relate::structurally_relate_consts(relation, a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ty::relate::structurally_relate_consts(relation, a, b),
|
||||
_ => relate::structurally_relate_consts(relation, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +304,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
||||
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> {
|
||||
fn span(&self) -> Span;
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx>;
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use std::mem;
|
||||
|
||||
use super::StructurallyRelateAliases;
|
||||
use super::{ObligationEmittingRelation, Relate, RelateResult, TypeRelation};
|
||||
use crate::infer::relate;
|
||||
use crate::infer::type_variable::TypeVariableValue;
|
||||
use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin};
|
||||
use crate::infer::{InferCtxt, RegionVariableOrigin};
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::unify_key::ConstVariableValue;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::MaxUniverse;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt};
|
||||
|
@ -228,7 +229,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
/// Attempts to generalize `source_term` for the type variable `target_vid`.
|
||||
/// This checks for cycles -- that is, whether `source_term` references `target_vid`.
|
||||
fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>(
|
||||
fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
span: Span,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
|
@ -395,7 +396,7 @@ impl<'tcx> Generalizer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
@ -430,10 +431,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, variance, b), ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -695,7 +696,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
_: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
||||
Ok(a.rebind(result))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Greatest lower bound. See [`lattice`].
|
||||
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use super::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
|
||||
fn tag(&self) -> &'static str {
|
||||
"Glb"
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
self.fields.tcx()
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
// GLB of a binder and itself is just itself
|
||||
if a == b {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::RelateResult;
|
||||
use crate::infer::snapshot::CombinedSnapshot;
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
|
|
@ -21,7 +21,7 @@ use super::combine::ObligationEmittingRelation;
|
|||
use crate::infer::{DefineOpaqueTypes, InferCtxt};
|
||||
use crate::traits::ObligationCause;
|
||||
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use super::RelateResult;
|
||||
use rustc_middle::ty::TyVar;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use super::StructurallyRelateAliases;
|
|||
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
|
||||
use crate::traits::{ObligationCause, PredicateObligations};
|
||||
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use super::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
|
||||
fn tag(&self) -> &'static str {
|
||||
"Lub"
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
self.fields.tcx()
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
// LUB of a binder and itself is just itself
|
||||
if a == b {
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
//! This module contains the definitions of most `TypeRelation`s in the type system
|
||||
//! (except for some relations used for diagnostics and heuristics in the compiler).
|
||||
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
|
||||
|
||||
pub use rustc_middle::ty::relate::*;
|
||||
|
||||
pub use self::_match::MatchAgainstFreshVars;
|
||||
pub use self::combine::CombineFields;
|
||||
pub use self::combine::ObligationEmittingRelation;
|
||||
|
||||
pub mod _match;
|
||||
pub(super) mod combine;
|
||||
mod generalize;
|
||||
mod glb;
|
||||
|
@ -8,15 +16,3 @@ mod higher_ranked;
|
|||
mod lattice;
|
||||
mod lub;
|
||||
mod type_relating;
|
||||
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
///
|
||||
/// This should always be `No` unless in a few special-cases when
|
||||
/// instantiating canonical responses and in the new solver. Each
|
||||
/// such case should have a comment explaining why it is used.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StructurallyRelateAliases {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use super::combine::CombineFields;
|
||||
use crate::infer::BoundRegionConversionTime::HigherRankedType;
|
||||
use crate::infer::{
|
||||
DefineOpaqueTypes, ObligationEmittingRelation, StructurallyRelateAliases, SubregionOrigin,
|
||||
};
|
||||
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
||||
use rustc_middle::ty::relate::{
|
||||
relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
|
||||
use super::{
|
||||
relate_args_invariantly, relate_args_with_variances, ObligationEmittingRelation, Relate,
|
||||
RelateResult, StructurallyRelateAliases, TypeRelation,
|
||||
};
|
||||
use rustc_middle::ty::TyVar;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -29,7 +28,7 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
|
||||
fn tag(&self) -> &'static str {
|
||||
"TypeRelating"
|
||||
}
|
||||
|
@ -56,10 +55,10 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
@ -226,7 +225,7 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
if a == b {
|
||||
// Do nothing
|
||||
|
|
|
@ -200,6 +200,12 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
fn def_id(self) -> DefId {
|
||||
self.did()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum AdtKind {
|
||||
Struct,
|
||||
|
|
|
@ -149,6 +149,10 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
||||
fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_target_usize(interner)
|
||||
}
|
||||
|
||||
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
|
||||
Const::new_infer(tcx, infer)
|
||||
}
|
||||
|
@ -168,6 +172,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
|||
fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
|
||||
Const::new_unevaluated(interner, uv)
|
||||
}
|
||||
|
||||
fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
|
||||
Const::new_expr(interner, expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
|
|
|
@ -69,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
|||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::WithCachedTypeInfo;
|
||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
||||
|
@ -135,9 +136,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type ParamEnv = ty::ParamEnv<'tcx>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
type Clause = Clause<'tcx>;
|
||||
|
||||
type Clauses = ty::Clauses<'tcx>;
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
}
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
}
|
||||
|
@ -148,6 +152,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.generics_of(def_id)
|
||||
}
|
||||
|
||||
type VariancesOf = &'tcx [ty::Variance];
|
||||
|
||||
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
|
||||
self.variances_of(def_id)
|
||||
}
|
||||
|
||||
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of(def_id)
|
||||
}
|
||||
|
@ -205,7 +215,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.mk_args(args)
|
||||
}
|
||||
|
||||
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs {
|
||||
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>,
|
||||
{
|
||||
self.mk_args_from_iter(args)
|
||||
}
|
||||
|
||||
|
@ -224,6 +238,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.arena.alloc(step)
|
||||
}
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::Ty, Self::Tys>,
|
||||
{
|
||||
self.mk_type_list_from_iter(args)
|
||||
}
|
||||
|
||||
fn parent(self, def_id: Self::DefId) -> Self::DefId {
|
||||
self.parent(def_id)
|
||||
}
|
||||
|
@ -231,6 +253,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
fn recursion_limit(self) -> usize {
|
||||
self.recursion_limit().0
|
||||
}
|
||||
|
||||
type Features = &'tcx rustc_feature::Features;
|
||||
|
||||
fn features(self) -> Self::Features {
|
||||
self.features()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
|
||||
|
@ -249,6 +277,12 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features {
|
||||
fn generic_const_exprs(self) -> bool {
|
||||
self.generic_const_exprs
|
||||
}
|
||||
}
|
||||
|
||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||
|
||||
pub struct CtxtInterners<'tcx> {
|
||||
|
|
|
@ -60,6 +60,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
|||
use rustc_span::{ExpnId, ExpnKind, Span};
|
||||
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||
pub use rustc_type_ir::relate::VarianceDiagInfo;
|
||||
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
||||
use tracing::{debug, instrument};
|
||||
pub use vtable::*;
|
||||
|
@ -114,7 +115,7 @@ pub use self::rvalue_scopes::RvalueScopes;
|
|||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||
CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
|
||||
ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
||||
ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
|
@ -122,7 +123,6 @@ pub use self::typeck_results::{
|
|||
TypeckResults, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
|
||||
pub mod _match;
|
||||
pub mod abstract_const;
|
||||
pub mod adjustment;
|
||||
pub mod cast;
|
||||
|
|
|
@ -1,383 +1,54 @@
|
|||
//! Generalized type relating mechanism.
|
||||
//!
|
||||
//! A type relation `R` relates a pair of values `(A, B)`. `A and B` are usually
|
||||
//! types or regions but can be other things. Examples of type relations are
|
||||
//! subtyping, type equality, etc.
|
||||
use std::iter;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_target::spec::abi;
|
||||
pub use rustc_type_ir::relate::*;
|
||||
|
||||
use crate::ty::error::{ExpectedFound, TypeError};
|
||||
use crate::ty::{
|
||||
self, ExistentialPredicate, ExistentialPredicateStableCmpExt as _, GenericArg, GenericArgKind,
|
||||
GenericArgsRef, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::TypeVisitable;
|
||||
use rustc_target::spec::abi;
|
||||
use std::iter;
|
||||
use tracing::{debug, instrument};
|
||||
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
|
||||
use crate::ty::{self as ty, Ty, TyCtxt};
|
||||
|
||||
use super::Pattern;
|
||||
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
|
||||
|
||||
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
|
||||
|
||||
pub trait TypeRelation<'tcx>: Sized {
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
|
||||
/// Returns a static string we can use for printouts.
|
||||
fn tag(&self) -> &'static str;
|
||||
|
||||
/// Generic relation routine suitable for most anything.
|
||||
fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
|
||||
Relate::relate(self, a, b)
|
||||
}
|
||||
|
||||
/// Relate the two args for the given item. The default
|
||||
/// is to look up the variance for the item and proceed
|
||||
/// accordingly.
|
||||
fn relate_item_args(
|
||||
&mut self,
|
||||
item_def_id: DefId,
|
||||
a_arg: GenericArgsRef<'tcx>,
|
||||
b_arg: GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
|
||||
debug!(
|
||||
"relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})",
|
||||
item_def_id, a_arg, b_arg
|
||||
);
|
||||
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true)
|
||||
}
|
||||
|
||||
/// Switch variance for the purpose of relating `a` and `b`.
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T>;
|
||||
|
||||
// Overridable relations. You shouldn't typically call these
|
||||
// directly, instead call `relate()`, which in turn calls
|
||||
// these. This is both more uniform but also allows us to add
|
||||
// additional hooks for other types in the future if needed
|
||||
// without making older code, which called `relate`, obsolete.
|
||||
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>;
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>>;
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>>;
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>;
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
///
|
||||
/// This should always be `No` unless in a few special-cases when
|
||||
/// instantiating canonical responses and in the new solver. Each
|
||||
/// such case should have a comment explaining why it is used.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StructurallyRelateAliases {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
pub trait Relate<'tcx>: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> RelateResult<'tcx, Self>;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Relate impls
|
||||
|
||||
#[inline]
|
||||
pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a_arg: GenericArgsRef<'tcx>,
|
||||
b_arg: GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
|
||||
relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| {
|
||||
relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn relate_args_with_variances<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
ty_def_id: DefId,
|
||||
variances: &[ty::Variance],
|
||||
a_arg: GenericArgsRef<'tcx>,
|
||||
b_arg: GenericArgsRef<'tcx>,
|
||||
fetch_ty_for_diag: bool,
|
||||
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
|
||||
let tcx = relation.tcx();
|
||||
|
||||
let mut cached_ty = None;
|
||||
let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| {
|
||||
let variance = variances[i];
|
||||
let variance_info = if variance == ty::Invariant && fetch_ty_for_diag {
|
||||
let ty =
|
||||
*cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg));
|
||||
ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
|
||||
} else {
|
||||
ty::VarianceDiagInfo::default()
|
||||
};
|
||||
relation.relate_with_variance(variance, variance_info, a, b)
|
||||
});
|
||||
|
||||
tcx.mk_args_from_iter(params)
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::FnSig<'tcx>,
|
||||
b: ty::FnSig<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::FnSig<'tcx>> {
|
||||
let tcx = relation.tcx();
|
||||
|
||||
if a.c_variadic != b.c_variadic {
|
||||
return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
|
||||
}
|
||||
let safety = relation.relate(a.safety, b.safety)?;
|
||||
let abi = relation.relate(a.abi, b.abi)?;
|
||||
|
||||
if a.inputs().len() != b.inputs().len() {
|
||||
return Err(TypeError::ArgCount);
|
||||
}
|
||||
|
||||
let inputs_and_output = iter::zip(a.inputs(), b.inputs())
|
||||
.map(|(&a, &b)| ((a, b), false))
|
||||
.chain(iter::once(((a.output(), b.output()), true)))
|
||||
.map(|((a, b), is_output)| {
|
||||
if is_output {
|
||||
relation.relate(a, b)
|
||||
} else {
|
||||
relation.relate_with_variance(
|
||||
ty::Contravariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a,
|
||||
b,
|
||||
)
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(i, r)| match r {
|
||||
Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
|
||||
Err(TypeError::ArgumentSorts(exp_found, i))
|
||||
}
|
||||
Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
|
||||
Err(TypeError::ArgumentMutability(i))
|
||||
}
|
||||
r => r,
|
||||
});
|
||||
Ok(ty::FnSig {
|
||||
inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?,
|
||||
c_variadic: a.c_variadic,
|
||||
safety,
|
||||
abi,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::BoundConstness {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
_relation: &mut R,
|
||||
a: ty::BoundConstness,
|
||||
b: ty::BoundConstness,
|
||||
) -> RelateResult<'tcx, ty::BoundConstness> {
|
||||
if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for hir::Safety {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
_relation: &mut R,
|
||||
a: hir::Safety,
|
||||
b: hir::Safety,
|
||||
) -> RelateResult<'tcx, hir::Safety> {
|
||||
if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for abi::Abi {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
_relation: &mut R,
|
||||
a: abi::Abi,
|
||||
b: abi::Abi,
|
||||
) -> RelateResult<'tcx, abi::Abi> {
|
||||
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::AliasTy<'tcx>,
|
||||
b: ty::AliasTy<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = match a.kind(relation.tcx()) {
|
||||
ty::Opaque => relate_args_with_variances(
|
||||
relation,
|
||||
a.def_id,
|
||||
relation.tcx().variances_of(a.def_id),
|
||||
a.args,
|
||||
b.args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::Projection | ty::Weak | ty::Inherent => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
}
|
||||
};
|
||||
Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::AliasTerm<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::AliasTerm<'tcx>,
|
||||
b: ty::AliasTerm<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::AliasTerm<'tcx>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = match a.kind(relation.tcx()) {
|
||||
ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
|
||||
relation,
|
||||
a.def_id,
|
||||
relation.tcx().variances_of(a.def_id),
|
||||
a.args,
|
||||
b.args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
}
|
||||
};
|
||||
Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::ExistentialProjection<'tcx>,
|
||||
b: ty::ExistentialProjection<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let term = relation.relate_with_variance(
|
||||
ty::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a.term,
|
||||
b.term,
|
||||
)?;
|
||||
let args = relation.relate_with_variance(
|
||||
ty::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a.args,
|
||||
b.args,
|
||||
)?;
|
||||
Ok(ty::ExistentialProjection { def_id: a.def_id, args, term })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::TraitRef<'tcx>,
|
||||
b: ty::TraitRef<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::ExistentialTraitRef<'tcx>,
|
||||
b: ty::ExistentialTraitRef<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Debug, Clone, TypeFoldable, TypeVisitable)]
|
||||
struct CoroutineWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>);
|
||||
|
||||
impl<'tcx> Relate<'tcx> for CoroutineWitness<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: CoroutineWitness<'tcx>,
|
||||
b: CoroutineWitness<'tcx>,
|
||||
) -> RelateResult<'tcx, CoroutineWitness<'tcx>> {
|
||||
assert_eq!(a.0.len(), b.0.len());
|
||||
let tcx = relation.tcx();
|
||||
let types =
|
||||
tcx.mk_type_list_from_iter(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?;
|
||||
Ok(CoroutineWitness(types))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> {
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> {
|
||||
#[inline]
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: ImplSubject<'tcx>,
|
||||
b: ImplSubject<'tcx>,
|
||||
) -> RelateResult<'tcx, ImplSubject<'tcx>> {
|
||||
a: ty::ImplSubject<'tcx>,
|
||||
b: ty::ImplSubject<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> {
|
||||
match (a, b) {
|
||||
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
|
||||
(ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => {
|
||||
let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
|
||||
Ok(ImplSubject::Trait(trait_ref))
|
||||
Ok(ty::ImplSubject::Trait(trait_ref))
|
||||
}
|
||||
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
|
||||
(ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => {
|
||||
let ty = Ty::relate(relation, ty_a, ty_b)?;
|
||||
Ok(ImplSubject::Inherent(ty))
|
||||
Ok(ty::ImplSubject::Inherent(ty))
|
||||
}
|
||||
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
|
||||
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
|
||||
(ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_))
|
||||
| (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => {
|
||||
bug!("can not relate TraitRef and Ty");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for Ty<'tcx> {
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||
#[inline]
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
|
@ -386,9 +57,9 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for Pattern<'tcx> {
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
|
||||
#[inline]
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: Self,
|
||||
b: Self,
|
||||
|
@ -416,276 +87,8 @@ impl<'tcx> Relate<'tcx> for Pattern<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of projections, and inference variables have to be
|
||||
/// handled by the caller.
|
||||
#[instrument(level = "trace", skip(relation), ret)]
|
||||
pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let tcx = relation.tcx();
|
||||
match (a.kind(), b.kind()) {
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
bug!("var types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(ty::Bound(..), _) | (_, ty::Bound(..)) => {
|
||||
bug!("bound types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)),
|
||||
|
||||
(&ty::Never, _)
|
||||
| (&ty::Char, _)
|
||||
| (&ty::Bool, _)
|
||||
| (&ty::Int(_), _)
|
||||
| (&ty::Uint(_), _)
|
||||
| (&ty::Float(_), _)
|
||||
| (&ty::Str, _)
|
||||
if a == b =>
|
||||
{
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => {
|
||||
debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
|
||||
|
||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) if a_def == b_def => {
|
||||
let args = relation.relate_item_args(a_def.did(), a_args, b_args)?;
|
||||
Ok(Ty::new_adt(tcx, a_def, args))
|
||||
}
|
||||
|
||||
(&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)),
|
||||
|
||||
(&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr))
|
||||
if a_repr == b_repr =>
|
||||
{
|
||||
Ok(Ty::new_dynamic(
|
||||
tcx,
|
||||
relation.relate(a_obj, b_obj)?,
|
||||
relation.relate(a_region, b_region)?,
|
||||
a_repr,
|
||||
))
|
||||
}
|
||||
|
||||
(&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => {
|
||||
// All Coroutine types with the same id represent
|
||||
// the (anonymous) type of the same coroutine expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(&ty::CoroutineWitness(a_id, a_args), &ty::CoroutineWitness(b_id, b_args))
|
||||
if a_id == b_id =>
|
||||
{
|
||||
// All CoroutineWitness types with the same id represent
|
||||
// the (anonymous) type of the same coroutine expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine_witness(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => {
|
||||
// All Closure types with the same id represent
|
||||
// the (anonymous) type of the same closure expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_closure(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args))
|
||||
if a_id == b_id =>
|
||||
{
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine_closure(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(&ty::RawPtr(a_ty, a_mutbl), &ty::RawPtr(b_ty, b_mutbl)) => {
|
||||
if a_mutbl != b_mutbl {
|
||||
return Err(TypeError::Mutability);
|
||||
}
|
||||
|
||||
let (variance, info) = match a_mutbl {
|
||||
hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
|
||||
hir::Mutability::Mut => {
|
||||
(ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
|
||||
}
|
||||
};
|
||||
|
||||
let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
|
||||
|
||||
Ok(Ty::new_ptr(tcx, ty, a_mutbl))
|
||||
}
|
||||
|
||||
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
|
||||
if a_mutbl != b_mutbl {
|
||||
return Err(TypeError::Mutability);
|
||||
}
|
||||
|
||||
let (variance, info) = match a_mutbl {
|
||||
hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
|
||||
hir::Mutability::Mut => {
|
||||
(ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
|
||||
}
|
||||
};
|
||||
|
||||
let r = relation.relate(a_r, b_r)?;
|
||||
let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
|
||||
|
||||
Ok(Ty::new_ref(tcx, r, ty, a_mutbl))
|
||||
}
|
||||
|
||||
(&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => {
|
||||
let t = relation.relate(a_t, b_t)?;
|
||||
match relation.relate(sz_a, sz_b) {
|
||||
Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)),
|
||||
Err(err) => {
|
||||
// Check whether the lengths are both concrete/known values,
|
||||
// but are unequal, for better diagnostics.
|
||||
let sz_a = sz_a.try_to_target_usize(tcx);
|
||||
let sz_b = sz_b.try_to_target_usize(tcx);
|
||||
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
|
||||
Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val)))
|
||||
}
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(&ty::Slice(a_t), &ty::Slice(b_t)) => {
|
||||
let t = relation.relate(a_t, b_t)?;
|
||||
Ok(Ty::new_slice(tcx, t))
|
||||
}
|
||||
|
||||
(&ty::Tuple(as_), &ty::Tuple(bs)) => {
|
||||
if as_.len() == bs.len() {
|
||||
Ok(Ty::new_tup_from_iter(
|
||||
tcx,
|
||||
iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
|
||||
)?)
|
||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
||||
Err(TypeError::TupleSize(expected_found(as_.len(), bs.len())))
|
||||
} else {
|
||||
Err(TypeError::Sorts(expected_found(a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
(&ty::FnDef(a_def_id, a_args), &ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
|
||||
let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
|
||||
Ok(Ty::new_fn_def(tcx, a_def_id, args))
|
||||
}
|
||||
|
||||
(&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => {
|
||||
let fty = relation.relate(a_fty, b_fty)?;
|
||||
Ok(Ty::new_fn_ptr(tcx, fty))
|
||||
}
|
||||
|
||||
// Alias tend to mostly already be handled downstream due to normalization.
|
||||
(&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
|
||||
let alias_ty = relation.relate(a_data, b_data)?;
|
||||
assert_eq!(a_kind, b_kind);
|
||||
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
|
||||
}
|
||||
|
||||
(&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => {
|
||||
let ty = relation.relate(a_ty, b_ty)?;
|
||||
let pat = relation.relate(a_pat, b_pat)?;
|
||||
Ok(Ty::new_pat(tcx, ty, pat))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Sorts(expected_found(a, b))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of unevaluated consts, and inference variables have
|
||||
/// to be handled by the caller.
|
||||
///
|
||||
/// FIXME: This is not totally structual, which probably should be fixed.
|
||||
/// See the HACKs below.
|
||||
pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
mut a: ty::Const<'tcx>,
|
||||
mut b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
|
||||
let tcx = relation.tcx();
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
a = tcx.expand_abstract_consts(a);
|
||||
b = tcx.expand_abstract_consts(b);
|
||||
}
|
||||
|
||||
debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
|
||||
|
||||
// Currently, the values that can be unified are primitive types,
|
||||
// and those that derive both `PartialEq` and `Eq`, corresponding
|
||||
// to structural-match types.
|
||||
let is_match = match (a.kind(), b.kind()) {
|
||||
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
|
||||
}
|
||||
|
||||
(ty::ConstKind::Error(_), _) => return Ok(a),
|
||||
(_, ty::ConstKind::Error(_)) => return Ok(b),
|
||||
|
||||
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
|
||||
debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
|
||||
true
|
||||
}
|
||||
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
|
||||
(ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val,
|
||||
|
||||
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
|
||||
// and is the better alternative to waiting until `generic_const_exprs` can
|
||||
// be stabilized.
|
||||
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
|
||||
if cfg!(debug_assertions) {
|
||||
let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args);
|
||||
let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args);
|
||||
assert_eq!(a_ty, b_ty);
|
||||
}
|
||||
|
||||
let args = relation.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
au.args,
|
||||
bu.args,
|
||||
)?;
|
||||
return Ok(ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args }));
|
||||
}
|
||||
(ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
|
||||
match (ae.kind, be.kind) {
|
||||
(ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop))
|
||||
if a_binop == b_binop => {}
|
||||
(ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {}
|
||||
(ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {}
|
||||
(ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {}
|
||||
_ => return Err(TypeError::ConstMismatch(expected_found(a, b))),
|
||||
}
|
||||
|
||||
let args = relation.relate(ae.args(), be.args())?;
|
||||
return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args)));
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) }
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: Self,
|
||||
b: Self,
|
||||
|
@ -703,44 +106,65 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
|||
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
b_v.dedup();
|
||||
if a_v.len() != b_v.len() {
|
||||
return Err(TypeError::ExistentialMismatch(expected_found(a, b)));
|
||||
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b)));
|
||||
}
|
||||
|
||||
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
|
||||
match (ep_a.skip_binder(), ep_b.skip_binder()) {
|
||||
(ExistentialPredicate::Trait(a), ExistentialPredicate::Trait(b)) => Ok(ep_a
|
||||
.rebind(ExistentialPredicate::Trait(
|
||||
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
|
||||
))),
|
||||
(ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => {
|
||||
Ok(ep_a.rebind(ExistentialPredicate::Projection(
|
||||
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
|
||||
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
|
||||
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
|
||||
)))
|
||||
}
|
||||
(ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b))
|
||||
if a == b =>
|
||||
{
|
||||
Ok(ep_a.rebind(ExistentialPredicate::AutoTrait(a)))
|
||||
}
|
||||
_ => Err(TypeError::ExistentialMismatch(expected_found(a, b))),
|
||||
(
|
||||
ty::ExistentialPredicate::Projection(a),
|
||||
ty::ExistentialPredicate::Projection(b),
|
||||
) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection(
|
||||
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
|
||||
))),
|
||||
(
|
||||
ty::ExistentialPredicate::AutoTrait(a),
|
||||
ty::ExistentialPredicate::AutoTrait(b),
|
||||
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
|
||||
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))),
|
||||
}
|
||||
});
|
||||
tcx.mk_poly_existential_predicates_from_iter(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for hir::Safety {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
_relation: &mut R,
|
||||
a: hir::Safety,
|
||||
b: hir::Safety,
|
||||
) -> RelateResult<'tcx, hir::Safety> {
|
||||
if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for abi::Abi {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
_relation: &mut R,
|
||||
a: abi::Abi,
|
||||
b: abi::Abi,
|
||||
) -> RelateResult<'tcx, abi::Abi> {
|
||||
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: GenericArgsRef<'tcx>,
|
||||
b: GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
|
||||
a: ty::GenericArgsRef<'tcx>,
|
||||
b: ty::GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
|
||||
relate_args_invariantly(relation, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::Region<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Region<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
|
@ -749,8 +173,8 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::Const<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
|
@ -759,85 +183,70 @@ impl<'tcx> Relate<'tcx> for ty::Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
|
||||
relation.binders(a, b)
|
||||
ae: ty::Expr<'tcx>,
|
||||
be: ty::Expr<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Expr<'tcx>> {
|
||||
// FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
|
||||
// exprs? Should we care about that?
|
||||
// FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to
|
||||
// ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought
|
||||
// of as being generic over the argument types, however this is implicit so these types don't get
|
||||
// related when we relate the args of the item this const arg is for.
|
||||
match (ae.kind, be.kind) {
|
||||
(ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {}
|
||||
(ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {}
|
||||
(ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {}
|
||||
(ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {}
|
||||
_ => return Err(TypeError::Mismatch),
|
||||
}
|
||||
|
||||
let args = relation.relate(ae.args(), be.args())?;
|
||||
Ok(ty::Expr::new(ae.kind, args))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: GenericArg<'tcx>,
|
||||
b: GenericArg<'tcx>,
|
||||
) -> RelateResult<'tcx, GenericArg<'tcx>> {
|
||||
a: ty::GenericArg<'tcx>,
|
||||
b: ty::GenericArg<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::GenericArg<'tcx>> {
|
||||
match (a.unpack(), b.unpack()) {
|
||||
(GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => {
|
||||
(ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => {
|
||||
Ok(relation.relate(a_lt, b_lt)?.into())
|
||||
}
|
||||
(GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => {
|
||||
(ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => {
|
||||
Ok(relation.relate(a_ty, b_ty)?.into())
|
||||
}
|
||||
(GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => {
|
||||
(ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => {
|
||||
Ok(relation.relate(a_ct, b_ct)?.into())
|
||||
}
|
||||
(GenericArgKind::Lifetime(unpacked), x) => {
|
||||
(ty::GenericArgKind::Lifetime(unpacked), x) => {
|
||||
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
|
||||
}
|
||||
(GenericArgKind::Type(unpacked), x) => {
|
||||
(ty::GenericArgKind::Type(unpacked), x) => {
|
||||
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
|
||||
}
|
||||
(GenericArgKind::Const(unpacked), x) => {
|
||||
(ty::GenericArgKind::Const(unpacked), x) => {
|
||||
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::PredicatePolarity {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
_relation: &mut R,
|
||||
a: ty::PredicatePolarity,
|
||||
b: ty::PredicatePolarity,
|
||||
) -> RelateResult<'tcx, ty::PredicatePolarity> {
|
||||
if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::TraitPredicate<'tcx>,
|
||||
b: ty::TraitPredicate<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> {
|
||||
Ok(ty::TraitPredicate {
|
||||
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
|
||||
polarity: relation.relate(a.polarity, b.polarity)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for Term<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> {
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
relation: &mut R,
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> RelateResult<'tcx, Self> {
|
||||
Ok(match (a.unpack(), b.unpack()) {
|
||||
(TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(),
|
||||
(TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(),
|
||||
(ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(),
|
||||
(ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(),
|
||||
_ => return Err(TypeError::Mismatch),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Error handling
|
||||
|
||||
pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> {
|
||||
ExpectedFound::new(true, a, b)
|
||||
}
|
||||
|
|
|
@ -810,6 +810,31 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
Ty::new_alias(interner, kind, alias_ty)
|
||||
}
|
||||
|
||||
fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
|
||||
Ty::new_error(interner, guar)
|
||||
}
|
||||
|
||||
fn new_adt(
|
||||
interner: TyCtxt<'tcx>,
|
||||
adt_def: ty::AdtDef<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Self {
|
||||
Ty::new_adt(interner, adt_def, args)
|
||||
}
|
||||
|
||||
fn new_foreign(interner: TyCtxt<'tcx>, def_id: DefId) -> Self {
|
||||
Ty::new_foreign(interner, def_id)
|
||||
}
|
||||
|
||||
fn new_dynamic(
|
||||
interner: TyCtxt<'tcx>,
|
||||
preds: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
region: ty::Region<'tcx>,
|
||||
kind: ty::DynKind,
|
||||
) -> Self {
|
||||
Ty::new_dynamic(interner, preds, region, kind)
|
||||
}
|
||||
|
||||
fn new_coroutine(
|
||||
interner: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
|
@ -818,6 +843,51 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
Ty::new_coroutine(interner, def_id, args)
|
||||
}
|
||||
|
||||
fn new_coroutine_closure(
|
||||
interner: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Self {
|
||||
Ty::new_coroutine_closure(interner, def_id, args)
|
||||
}
|
||||
|
||||
fn new_closure(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self {
|
||||
Ty::new_closure(interner, def_id, args)
|
||||
}
|
||||
|
||||
fn new_coroutine_witness(
|
||||
interner: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Self {
|
||||
Ty::new_coroutine_witness(interner, def_id, args)
|
||||
}
|
||||
|
||||
fn new_ptr(interner: TyCtxt<'tcx>, ty: Self, mutbl: hir::Mutability) -> Self {
|
||||
Ty::new_ptr(interner, ty, mutbl)
|
||||
}
|
||||
|
||||
fn new_ref(
|
||||
interner: TyCtxt<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
ty: Self,
|
||||
mutbl: hir::Mutability,
|
||||
) -> Self {
|
||||
Ty::new_ref(interner, region, ty, mutbl)
|
||||
}
|
||||
|
||||
fn new_array_with_const_len(interner: TyCtxt<'tcx>, ty: Self, len: ty::Const<'tcx>) -> Self {
|
||||
Ty::new_array_with_const_len(interner, ty, len)
|
||||
}
|
||||
|
||||
fn new_slice(interner: TyCtxt<'tcx>, ty: Self) -> Self {
|
||||
Ty::new_slice(interner, ty)
|
||||
}
|
||||
|
||||
fn new_tup(interner: TyCtxt<'tcx>, tys: &[Ty<'tcx>]) -> Self {
|
||||
Ty::new_tup(interner, tys)
|
||||
}
|
||||
|
||||
fn new_tup_from_iter<It, T>(interner: TyCtxt<'tcx>, iter: It) -> T::Output
|
||||
where
|
||||
It: Iterator<Item = T>,
|
||||
|
@ -844,6 +914,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
) -> Self {
|
||||
Ty::from_coroutine_closure_kind(interner, kind)
|
||||
}
|
||||
|
||||
fn new_fn_def(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self {
|
||||
Ty::new_fn_def(interner, def_id, args)
|
||||
}
|
||||
|
||||
fn new_fn_ptr(interner: TyCtxt<'tcx>, sig: ty::Binder<'tcx, ty::FnSig<'tcx>>) -> Self {
|
||||
Ty::new_fn_ptr(interner, sig)
|
||||
}
|
||||
|
||||
fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self {
|
||||
Ty::new_pat(interner, ty, pat)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type utilities
|
||||
|
@ -1812,43 +1894,6 @@ impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// Extra information about why we ended up with a particular variance.
|
||||
/// This is only used to add more information to error messages, and
|
||||
/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
|
||||
/// may lead to confusing notes in error messages, it will never cause
|
||||
/// a miscompilation or unsoundness.
|
||||
///
|
||||
/// When in doubt, use `VarianceDiagInfo::default()`
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum VarianceDiagInfo<'tcx> {
|
||||
/// No additional information - this is the default.
|
||||
/// We will not add any additional information to error messages.
|
||||
#[default]
|
||||
None,
|
||||
/// We switched our variance because a generic argument occurs inside
|
||||
/// the invariant generic argument of another type.
|
||||
Invariant {
|
||||
/// The generic type containing the generic parameter
|
||||
/// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
|
||||
ty: Ty<'tcx>,
|
||||
/// The index of the generic parameter being used
|
||||
/// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
|
||||
param_index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> VarianceDiagInfo<'tcx> {
|
||||
/// Mirrors `Variance::xform` - used to 'combine' the existing
|
||||
/// and new `VarianceDiagInfo`s when our variance changes.
|
||||
pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
|
||||
// For now, just use the first `VarianceDiagInfo::Invariant` that we see
|
||||
match self {
|
||||
VarianceDiagInfo::None => other,
|
||||
VarianceDiagInfo::Invariant { .. } => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
|
@ -4,13 +4,16 @@ version = "0.0.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
||||
# tidy-alphabetical-start
|
||||
derivative = "2.2.0"
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
|
|
|
@ -7,11 +7,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
|||
// EAGER RESOLUTION
|
||||
|
||||
/// Resolves ty, region, and const vars to their inferred values or their root vars.
|
||||
pub struct EagerResolver<
|
||||
'a,
|
||||
pub struct EagerResolver<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner = <Infcx as InferCtxtLike>::Interner,
|
||||
> {
|
||||
I: Interner,
|
||||
{
|
||||
infcx: &'a Infcx,
|
||||
}
|
||||
|
||||
|
|
|
@ -37,11 +37,11 @@ pub(super) mod canonical;
|
|||
mod probe;
|
||||
mod select;
|
||||
|
||||
pub struct EvalCtxt<
|
||||
'a,
|
||||
pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner = <Infcx as InferCtxtLike>::Interner,
|
||||
> {
|
||||
I: Interner,
|
||||
{
|
||||
/// The inference context that backs (mostly) inference and placeholder terms
|
||||
/// instantiated while solving goals.
|
||||
///
|
||||
|
|
|
@ -32,6 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
|||
use rustc_errors::{Diag, EmissionGuarantee};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::relate::MatchAgainstFreshVars;
|
||||
use rustc_infer::infer::relate::TypeRelation;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
|
@ -40,11 +42,9 @@ use rustc_middle::bug;
|
|||
use rustc_middle::dep_graph::dep_kinds;
|
||||
use rustc_middle::dep_graph::DepNodeIndex;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::_match::MatchAgainstFreshVars;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::TypeErrorToStringExt;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast};
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
|
|
|
@ -7,7 +7,10 @@ use std::fmt::Debug;
|
|||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_ast_ir::Mutability;
|
||||
|
||||
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
||||
use crate::relate::Relate;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom};
|
||||
|
||||
|
@ -21,6 +24,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
|||
+ IntoKind<Kind = ty::TyKind<I>>
|
||||
+ TypeSuperVisitable<I>
|
||||
+ TypeSuperFoldable<I>
|
||||
+ Relate<I>
|
||||
+ Flags
|
||||
{
|
||||
fn new_bool(interner: I) -> Self;
|
||||
|
@ -35,8 +39,37 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
|||
|
||||
fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
|
||||
|
||||
fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self;
|
||||
|
||||
fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_foreign(interner: I, def_id: I::DefId) -> Self;
|
||||
|
||||
fn new_dynamic(
|
||||
interner: I,
|
||||
preds: I::BoundExistentialPredicates,
|
||||
region: I::Region,
|
||||
kind: ty::DynKind,
|
||||
) -> Self;
|
||||
|
||||
fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_ptr(interner: I, ty: Self, mutbl: Mutability) -> Self;
|
||||
|
||||
fn new_ref(interner: I, region: I::Region, ty: Self, mutbl: Mutability) -> Self;
|
||||
|
||||
fn new_array_with_const_len(interner: I, ty: Self, len: I::Const) -> Self;
|
||||
|
||||
fn new_slice(interner: I, ty: Self) -> Self;
|
||||
|
||||
fn new_tup(interner: I, tys: &[I::Ty]) -> Self;
|
||||
|
||||
fn new_tup_from_iter<It, T>(interner: I, iter: It) -> T::Output
|
||||
where
|
||||
It: Iterator<Item = T>,
|
||||
|
@ -49,6 +82,12 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
|||
fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
|
||||
|
||||
fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
|
||||
|
||||
fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
|
||||
|
||||
fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
|
||||
}
|
||||
|
||||
pub trait Tys<I: Interner<Tys = Self>>:
|
||||
|
@ -84,6 +123,7 @@ pub trait Region<I: Interner<Region = Self>>:
|
|||
+ IntoKind<Kind = ty::RegionKind<I>>
|
||||
+ Flags
|
||||
+ TypeVisitable<I>
|
||||
+ Relate<I>
|
||||
{
|
||||
fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self;
|
||||
|
||||
|
@ -102,8 +142,11 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
+ IntoKind<Kind = ty::ConstKind<I>>
|
||||
+ TypeSuperVisitable<I>
|
||||
+ TypeSuperFoldable<I>
|
||||
+ Relate<I>
|
||||
+ Flags
|
||||
{
|
||||
fn try_to_target_usize(self, interner: I) -> Option<u64>;
|
||||
|
||||
fn new_infer(interner: I, var: ty::InferConst) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: ty::ConstVid) -> Self;
|
||||
|
@ -113,6 +156,8 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self;
|
||||
|
||||
fn new_expr(interner: I, expr: I::ExprConst) -> Self;
|
||||
}
|
||||
|
||||
pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
|
||||
|
@ -128,13 +173,14 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
|||
+ Deref<Target: Deref<Target = [I::GenericArg]>>
|
||||
+ Default
|
||||
+ TypeFoldable<I>
|
||||
+ Relate<I>
|
||||
{
|
||||
fn type_at(self, i: usize) -> I::Ty;
|
||||
|
||||
fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
|
||||
|
||||
fn extend_with_error(
|
||||
tcx: I,
|
||||
interner: I,
|
||||
def_id: I::DefId,
|
||||
original_args: &[I::GenericArg],
|
||||
) -> I::GenericArgs;
|
||||
|
@ -193,3 +239,11 @@ pub trait BoundVarLike<I: Interner> {
|
|||
pub trait ParamLike {
|
||||
fn index(self) -> u32;
|
||||
}
|
||||
|
||||
pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
fn def_id(self) -> I::DefId;
|
||||
}
|
||||
|
||||
pub trait Features<I: Interner>: Copy {
|
||||
fn generic_const_exprs(self) -> bool;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::ops::Deref;
|
|||
use crate::fold::TypeFoldable;
|
||||
use crate::inherent::*;
|
||||
use crate::ir_print::IrPrint;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, DebugWithInfcx};
|
||||
|
@ -25,8 +26,8 @@ pub trait Interner:
|
|||
+ IrPrint<ty::CoercePredicate<Self>>
|
||||
+ IrPrint<ty::FnSig<Self>>
|
||||
{
|
||||
type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>;
|
||||
type AdtDef: Copy + Debug + Hash + Eq;
|
||||
type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
|
||||
type AdtDef: AdtDef<Self>;
|
||||
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
||||
|
@ -35,8 +36,15 @@ pub trait Interner:
|
|||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
||||
+ TypeVisitable<Self>;
|
||||
type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<Self>> + TypeVisitable<Self>;
|
||||
+ TypeVisitable<Self>
|
||||
+ Relate<Self>;
|
||||
type Term: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::TermKind<Self>>
|
||||
+ TypeFoldable<Self>
|
||||
+ Relate<Self>;
|
||||
|
||||
type BoundVarKinds: Copy
|
||||
+ Debug
|
||||
|
@ -66,11 +74,11 @@ pub trait Interner:
|
|||
|
||||
// Things stored inside of tys
|
||||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>;
|
||||
type AllocId: Copy + Debug + Hash + Eq;
|
||||
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
|
||||
type Safety: Safety<Self>;
|
||||
type Abi: Abi<Self>;
|
||||
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self> + Relate<Self>;
|
||||
type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||
type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||
|
||||
// Kinds of consts
|
||||
type Const: Const<Self>;
|
||||
|
@ -78,7 +86,7 @@ pub trait Interner:
|
|||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type ValueConst: Copy + Debug + Hash + Eq;
|
||||
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>;
|
||||
|
||||
// Kinds of regions
|
||||
type Region: Region<Self>;
|
||||
|
@ -93,11 +101,16 @@ pub trait Interner:
|
|||
type Clause: Clause<Self>;
|
||||
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
|
||||
type GenericsOf: GenericsOf<Self>;
|
||||
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
|
||||
|
||||
type VariancesOf: Copy + Debug + Deref<Target = [ty::Variance]>;
|
||||
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
|
||||
|
||||
// FIXME: Remove after uplifting `EarlyBinder`
|
||||
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
|
||||
|
||||
|
@ -112,7 +125,12 @@ pub trait Interner:
|
|||
) -> (ty::TraitRef<Self>, Self::GenericArgsSlice);
|
||||
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
|
||||
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
|
||||
|
||||
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>;
|
||||
|
||||
fn check_and_mk_args(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
|
@ -124,9 +142,17 @@ pub trait Interner:
|
|||
step: CanonicalGoalEvaluationStep<Self>,
|
||||
) -> Self::CanonicalGoalEvaluationStepRef;
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::Ty, Self::Tys>;
|
||||
|
||||
fn parent(self, def_id: Self::DefId) -> Self::DefId;
|
||||
|
||||
fn recursion_limit(self) -> usize;
|
||||
|
||||
type Features: Features<Self>;
|
||||
fn features(self) -> Self::Features;
|
||||
}
|
||||
|
||||
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
||||
|
|
|
@ -31,6 +31,7 @@ pub mod fold;
|
|||
pub mod inherent;
|
||||
pub mod ir_print;
|
||||
pub mod lift;
|
||||
pub mod relate;
|
||||
pub mod solve;
|
||||
|
||||
// These modules are not `pub` since they are glob-imported.
|
||||
|
|
666
compiler/rustc_type_ir/src/relate.rs
Normal file
666
compiler/rustc_type_ir/src/relate.rs
Normal file
|
@ -0,0 +1,666 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_ast_ir::Mutability;
|
||||
use rustc_type_ir::error::{ExpectedFound, TypeError};
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub type RelateResult<I, T> = Result<T, TypeError<I>>;
|
||||
|
||||
/// Extra information about why we ended up with a particular variance.
|
||||
/// This is only used to add more information to error messages, and
|
||||
/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
|
||||
/// may lead to confusing notes in error messages, it will never cause
|
||||
/// a miscompilation or unsoundness.
|
||||
///
|
||||
/// When in doubt, use `VarianceDiagInfo::default()`
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Copy(bound = ""),
|
||||
Clone(bound = ""),
|
||||
Debug(bound = ""),
|
||||
Default(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Eq(bound = "")
|
||||
)]
|
||||
pub enum VarianceDiagInfo<I: Interner> {
|
||||
/// No additional information - this is the default.
|
||||
/// We will not add any additional information to error messages.
|
||||
#[derivative(Default)]
|
||||
None,
|
||||
/// We switched our variance because a generic argument occurs inside
|
||||
/// the invariant generic argument of another type.
|
||||
Invariant {
|
||||
/// The generic type containing the generic parameter
|
||||
/// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
|
||||
ty: I::Ty,
|
||||
/// The index of the generic parameter being used
|
||||
/// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
|
||||
param_index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<I: Interner> VarianceDiagInfo<I> {
|
||||
/// Mirrors `Variance::xform` - used to 'combine' the existing
|
||||
/// and new `VarianceDiagInfo`s when our variance changes.
|
||||
pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> {
|
||||
// For now, just use the first `VarianceDiagInfo::Invariant` that we see
|
||||
match self {
|
||||
VarianceDiagInfo::None => other,
|
||||
VarianceDiagInfo::Invariant { .. } => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeRelation<I: Interner>: Sized {
|
||||
fn tcx(&self) -> I;
|
||||
|
||||
/// Returns a static string we can use for printouts.
|
||||
fn tag(&self) -> &'static str;
|
||||
|
||||
/// Generic relation routine suitable for most anything.
|
||||
fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> {
|
||||
Relate::relate(self, a, b)
|
||||
}
|
||||
|
||||
/// Relate the two args for the given item. The default
|
||||
/// is to look up the variance for the item and proceed
|
||||
/// accordingly.
|
||||
fn relate_item_args(
|
||||
&mut self,
|
||||
item_def_id: I::DefId,
|
||||
a_arg: I::GenericArgs,
|
||||
b_arg: I::GenericArgs,
|
||||
) -> RelateResult<I, I::GenericArgs> {
|
||||
debug!(
|
||||
"relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})",
|
||||
item_def_id, a_arg, b_arg
|
||||
);
|
||||
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
relate_args_with_variances(self, item_def_id, &opt_variances, a_arg, b_arg, true)
|
||||
}
|
||||
|
||||
/// Switch variance for the purpose of relating `a` and `b`.
|
||||
fn relate_with_variance<T: Relate<I>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: VarianceDiagInfo<I>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<I, T>;
|
||||
|
||||
// Overridable relations. You shouldn't typically call these
|
||||
// directly, instead call `relate()`, which in turn calls
|
||||
// these. This is both more uniform but also allows us to add
|
||||
// additional hooks for other types in the future if needed
|
||||
// without making older code, which called `relate`, obsolete.
|
||||
|
||||
fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>;
|
||||
|
||||
fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region>;
|
||||
|
||||
fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>;
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<I, T>,
|
||||
b: ty::Binder<I, T>,
|
||||
) -> RelateResult<I, ty::Binder<I, T>>
|
||||
where
|
||||
T: Relate<I>;
|
||||
}
|
||||
|
||||
pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy {
|
||||
fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Relate impls
|
||||
|
||||
#[inline]
|
||||
pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a_arg: I::GenericArgs,
|
||||
b_arg: I::GenericArgs,
|
||||
) -> RelateResult<I, I::GenericArgs> {
|
||||
relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| {
|
||||
relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
ty_def_id: I::DefId,
|
||||
variances: &[ty::Variance],
|
||||
a_arg: I::GenericArgs,
|
||||
b_arg: I::GenericArgs,
|
||||
fetch_ty_for_diag: bool,
|
||||
) -> RelateResult<I, I::GenericArgs> {
|
||||
let tcx = relation.tcx();
|
||||
|
||||
let mut cached_ty = None;
|
||||
let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| {
|
||||
let variance = variances[i];
|
||||
let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag {
|
||||
let ty =
|
||||
*cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg));
|
||||
VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
|
||||
} else {
|
||||
VarianceDiagInfo::default()
|
||||
};
|
||||
relation.relate_with_variance(variance, variance_info, a, b)
|
||||
});
|
||||
|
||||
tcx.mk_args_from_iter(params)
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::FnSig<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::FnSig<I>,
|
||||
b: ty::FnSig<I>,
|
||||
) -> RelateResult<I, ty::FnSig<I>> {
|
||||
let tcx = relation.tcx();
|
||||
|
||||
if a.c_variadic != b.c_variadic {
|
||||
return Err(TypeError::VariadicMismatch({
|
||||
let a = a.c_variadic;
|
||||
let b = b.c_variadic;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}));
|
||||
}
|
||||
let safety = relation.relate(a.safety, b.safety)?;
|
||||
let abi = relation.relate(a.abi, b.abi)?;
|
||||
|
||||
let a_inputs = a.inputs();
|
||||
let b_inputs = b.inputs();
|
||||
|
||||
if a_inputs.len() != b_inputs.len() {
|
||||
return Err(TypeError::ArgCount);
|
||||
}
|
||||
|
||||
let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter())
|
||||
.map(|(&a, &b)| ((a, b), false))
|
||||
.chain(iter::once(((a.output(), b.output()), true)))
|
||||
.map(|((a, b), is_output)| {
|
||||
if is_output {
|
||||
relation.relate(a, b)
|
||||
} else {
|
||||
relation.relate_with_variance(
|
||||
ty::Variance::Contravariant,
|
||||
VarianceDiagInfo::default(),
|
||||
a,
|
||||
b,
|
||||
)
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(i, r)| match r {
|
||||
Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
|
||||
Err(TypeError::ArgumentSorts(exp_found, i))
|
||||
}
|
||||
Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
|
||||
Err(TypeError::ArgumentMutability(i))
|
||||
}
|
||||
r => r,
|
||||
});
|
||||
Ok(ty::FnSig {
|
||||
inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?,
|
||||
c_variadic: a.c_variadic,
|
||||
safety,
|
||||
abi,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::BoundConstness {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
_relation: &mut R,
|
||||
a: ty::BoundConstness,
|
||||
b: ty::BoundConstness,
|
||||
) -> RelateResult<I, ty::BoundConstness> {
|
||||
if a != b {
|
||||
Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b)))
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::AliasTy<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::AliasTy<I>,
|
||||
b: ty::AliasTy<I>,
|
||||
) -> RelateResult<I, ty::AliasTy<I>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched({
|
||||
let a = a.def_id;
|
||||
let b = b.def_id;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}))
|
||||
} else {
|
||||
let args = match a.kind(relation.tcx()) {
|
||||
ty::Opaque => relate_args_with_variances(
|
||||
relation,
|
||||
a.def_id,
|
||||
&relation.tcx().variances_of(a.def_id),
|
||||
a.args,
|
||||
b.args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::Projection | ty::Weak | ty::Inherent => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
}
|
||||
};
|
||||
Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::AliasTerm<I>,
|
||||
b: ty::AliasTerm<I>,
|
||||
) -> RelateResult<I, ty::AliasTerm<I>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched({
|
||||
let a = a.def_id;
|
||||
let b = b.def_id;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}))
|
||||
} else {
|
||||
let args = match a.kind(relation.tcx()) {
|
||||
ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
|
||||
relation,
|
||||
a.def_id,
|
||||
&relation.tcx().variances_of(a.def_id),
|
||||
a.args,
|
||||
b.args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
}
|
||||
};
|
||||
Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::ExistentialProjection<I>,
|
||||
b: ty::ExistentialProjection<I>,
|
||||
) -> RelateResult<I, ty::ExistentialProjection<I>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched({
|
||||
let a = a.def_id;
|
||||
let b = b.def_id;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}))
|
||||
} else {
|
||||
let term = relation.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
VarianceDiagInfo::default(),
|
||||
a.term,
|
||||
b.term,
|
||||
)?;
|
||||
let args = relation.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
VarianceDiagInfo::default(),
|
||||
a.args,
|
||||
b.args,
|
||||
)?;
|
||||
Ok(ty::ExistentialProjection { def_id: a.def_id, args, term })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::TraitRef<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::TraitRef<I>,
|
||||
b: ty::TraitRef<I>,
|
||||
) -> RelateResult<I, ty::TraitRef<I>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits({
|
||||
let a = a.def_id;
|
||||
let b = b.def_id;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::ExistentialTraitRef<I>,
|
||||
b: ty::ExistentialTraitRef<I>,
|
||||
) -> RelateResult<I, ty::ExistentialTraitRef<I>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits({
|
||||
let a = a.def_id;
|
||||
let b = b.def_id;
|
||||
ExpectedFound::new(true, a, b)
|
||||
}))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of projections, and inference variables have to be
|
||||
/// handled by the caller.
|
||||
#[instrument(level = "trace", skip(relation), ret)]
|
||||
pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: I::Ty,
|
||||
b: I::Ty,
|
||||
) -> RelateResult<I, I::Ty> {
|
||||
let tcx = relation.tcx();
|
||||
match (a.kind(), b.kind()) {
|
||||
(ty::Infer(_), _) | (_, ty::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
panic!("var types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(ty::Bound(..), _) | (_, ty::Bound(..)) => {
|
||||
panic!("bound types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)),
|
||||
|
||||
(ty::Never, _)
|
||||
| (ty::Char, _)
|
||||
| (ty::Bool, _)
|
||||
| (ty::Int(_), _)
|
||||
| (ty::Uint(_), _)
|
||||
| (ty::Float(_), _)
|
||||
| (ty::Str, _)
|
||||
if a == b =>
|
||||
{
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => {
|
||||
// FIXME: Put this back
|
||||
//debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name");
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
|
||||
|
||||
(ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => {
|
||||
let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?;
|
||||
Ok(Ty::new_adt(tcx, a_def, args))
|
||||
}
|
||||
|
||||
(ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)),
|
||||
|
||||
(ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr))
|
||||
if a_repr == b_repr =>
|
||||
{
|
||||
Ok(Ty::new_dynamic(
|
||||
tcx,
|
||||
relation.relate(a_obj, b_obj)?,
|
||||
relation.relate(a_region, b_region)?,
|
||||
a_repr,
|
||||
))
|
||||
}
|
||||
|
||||
(ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
|
||||
// All Coroutine types with the same id represent
|
||||
// the (anonymous) type of the same coroutine expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args))
|
||||
if a_id == b_id =>
|
||||
{
|
||||
// All CoroutineWitness types with the same id represent
|
||||
// the (anonymous) type of the same coroutine expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine_witness(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => {
|
||||
// All Closure types with the same id represent
|
||||
// the (anonymous) type of the same closure expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_closure(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args))
|
||||
if a_id == b_id =>
|
||||
{
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_coroutine_closure(tcx, a_id, args))
|
||||
}
|
||||
|
||||
(ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
|
||||
if a_mutbl != b_mutbl {
|
||||
return Err(TypeError::Mutability);
|
||||
}
|
||||
|
||||
let (variance, info) = match a_mutbl {
|
||||
Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None),
|
||||
Mutability::Mut => {
|
||||
(ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
|
||||
}
|
||||
};
|
||||
|
||||
let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
|
||||
|
||||
Ok(Ty::new_ptr(tcx, ty, a_mutbl))
|
||||
}
|
||||
|
||||
(ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => {
|
||||
if a_mutbl != b_mutbl {
|
||||
return Err(TypeError::Mutability);
|
||||
}
|
||||
|
||||
let (variance, info) = match a_mutbl {
|
||||
Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None),
|
||||
Mutability::Mut => {
|
||||
(ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
|
||||
}
|
||||
};
|
||||
|
||||
let r = relation.relate(a_r, b_r)?;
|
||||
let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
|
||||
|
||||
Ok(Ty::new_ref(tcx, r, ty, a_mutbl))
|
||||
}
|
||||
|
||||
(ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => {
|
||||
let t = relation.relate(a_t, b_t)?;
|
||||
match relation.relate(sz_a, sz_b) {
|
||||
Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)),
|
||||
Err(err) => {
|
||||
// Check whether the lengths are both concrete/known values,
|
||||
// but are unequal, for better diagnostics.
|
||||
let sz_a = sz_a.try_to_target_usize(tcx);
|
||||
let sz_b = sz_b.try_to_target_usize(tcx);
|
||||
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
|
||||
TypeError::FixedArraySize(ExpectedFound::new(true, sz_a_val, sz_b_val)),
|
||||
),
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(ty::Slice(a_t), ty::Slice(b_t)) => {
|
||||
let t = relation.relate(a_t, b_t)?;
|
||||
Ok(Ty::new_slice(tcx, t))
|
||||
}
|
||||
|
||||
(ty::Tuple(as_), ty::Tuple(bs)) => {
|
||||
if as_.len() == bs.len() {
|
||||
Ok(Ty::new_tup_from_iter(
|
||||
tcx,
|
||||
iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
|
||||
)?)
|
||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
||||
Err(TypeError::TupleSize(ExpectedFound::new(true, as_.len(), bs.len())))
|
||||
} else {
|
||||
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
(ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
|
||||
let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
|
||||
Ok(Ty::new_fn_def(tcx, a_def_id, args))
|
||||
}
|
||||
|
||||
(ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => {
|
||||
let fty = relation.relate(a_fty, b_fty)?;
|
||||
Ok(Ty::new_fn_ptr(tcx, fty))
|
||||
}
|
||||
|
||||
// Alias tend to mostly already be handled downstream due to normalization.
|
||||
(ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => {
|
||||
let alias_ty = relation.relate(a_data, b_data)?;
|
||||
assert_eq!(a_kind, b_kind);
|
||||
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
|
||||
}
|
||||
|
||||
(ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
|
||||
let ty = relation.relate(a_ty, b_ty)?;
|
||||
let pat = relation.relate(a_pat, b_pat)?;
|
||||
Ok(Ty::new_pat(tcx, ty, pat))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of unevaluated consts, and inference variables have
|
||||
/// to be handled by the caller.
|
||||
///
|
||||
/// FIXME: This is not totally structual, which probably should be fixed.
|
||||
/// See the HACKs below.
|
||||
pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
mut a: I::Const,
|
||||
mut b: I::Const,
|
||||
) -> RelateResult<I, I::Const> {
|
||||
debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
|
||||
let tcx = relation.tcx();
|
||||
|
||||
if tcx.features().generic_const_exprs() {
|
||||
a = tcx.expand_abstract_consts(a);
|
||||
b = tcx.expand_abstract_consts(b);
|
||||
}
|
||||
|
||||
debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
|
||||
|
||||
// Currently, the values that can be unified are primitive types,
|
||||
// and those that derive both `PartialEq` and `Eq`, corresponding
|
||||
// to structural-match types.
|
||||
let is_match = match (a.kind(), b.kind()) {
|
||||
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
|
||||
}
|
||||
|
||||
(ty::ConstKind::Error(_), _) => return Ok(a),
|
||||
(_, ty::ConstKind::Error(_)) => return Ok(b),
|
||||
|
||||
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => {
|
||||
// FIXME: Put this back
|
||||
// debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
|
||||
true
|
||||
}
|
||||
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
|
||||
(ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val,
|
||||
|
||||
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
|
||||
// and is the better alternative to waiting until `generic_const_exprs` can
|
||||
// be stabilized.
|
||||
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
|
||||
if cfg!(debug_assertions) {
|
||||
let a_ty = tcx.type_of(au.def).instantiate(tcx, &au.args);
|
||||
let b_ty = tcx.type_of(bu.def).instantiate(tcx, &bu.args);
|
||||
assert_eq!(a_ty, b_ty);
|
||||
}
|
||||
|
||||
let args = relation.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
VarianceDiagInfo::default(),
|
||||
au.args,
|
||||
bu.args,
|
||||
)?;
|
||||
return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args }));
|
||||
}
|
||||
(ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
|
||||
let expr = relation.relate(ae, be)?;
|
||||
return Ok(Const::new_expr(tcx, expr));
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))) }
|
||||
}
|
||||
|
||||
impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::Binder<I, T>,
|
||||
b: ty::Binder<I, T>,
|
||||
) -> RelateResult<I, ty::Binder<I, T>> {
|
||||
relation.binders(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::PredicatePolarity {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
_relation: &mut R,
|
||||
a: ty::PredicatePolarity,
|
||||
b: ty::PredicatePolarity,
|
||||
) -> RelateResult<I, ty::PredicatePolarity> {
|
||||
if a != b {
|
||||
Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b)))
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Relate<I> for ty::TraitPredicate<I> {
|
||||
fn relate<R: TypeRelation<I>>(
|
||||
relation: &mut R,
|
||||
a: ty::TraitPredicate<I>,
|
||||
b: ty::TraitPredicate<I>,
|
||||
) -> RelateResult<I, ty::TraitPredicate<I>> {
|
||||
Ok(ty::TraitPredicate {
|
||||
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
|
||||
polarity: relation.relate(a.polarity, b.polarity)?,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue