Implement TypeRelation::consts

Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
This commit is contained in:
varkor 2019-03-08 01:19:13 +00:00
parent 7d71a1c8a4
commit bfc39b9b87
9 changed files with 315 additions and 18 deletions

View File

@ -10,10 +10,11 @@ use crate::infer::canonical::{
OriginalQueryValues,
};
use crate::infer::InferCtxt;
use crate::mir::interpret::ConstValue;
use std::sync::atomic::Ordering;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::Kind;
use crate::ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
@ -432,6 +433,54 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
}
}
}
fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
if let ty::LazyConst::Evaluated(ct) = c {
match ct.val {
ConstValue::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.unwrap().probe_const_var(vid) {
Ok(c) => {
debug!("(resolved to {:?})", c);
return self.fold_const(c);
}
// `ConstVar(vid)` is unresolved, track its universe index in the
// canonicalized result
Err(mut ui) => {
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
}
return self.canonicalize_const_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Const(ui)
},
c
);
}
}
}
ConstValue::Infer(InferConst::Fresh(_)) => {
bug!("encountered a fresh const during canonicalization")
}
ConstValue::Infer(InferConst::Canonical(debruijn, _)) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
return c;
}
}
_ => {}
}
}
if c.type_flags().intersects(self.needs_canonical_flags) {
c.super_fold_with(self)
} else {
c
}
}
}
impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
@ -625,7 +674,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
/// `ty_var`.
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.infcx.expect("encountered ty-var without infcx");
let bound_to = infcx.shallow_resolve(ty_var);
let bound_to = infcx.shallow_resolve_type(ty_var);
if bound_to != ty_var {
self.fold_ty(bound_to)
} else {

View File

@ -464,7 +464,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
debug!("generalize: t={:?}", t);
// Check to see whether the type we are genealizing references
// Check to see whether the type we are generalizing references
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
@ -576,6 +576,32 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
// very descriptive origin for this region variable.
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
}
fn consts(
&mut self,
c: &'tcx ty::LazyConst<'tcx>,
c2: &'tcx ty::LazyConst<'tcx>
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
match c {
LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Var(vid)),
..
}) => {
let mut variable_table = self.infcx.const_unification_table.borrow_mut();
match variable_table.probe(*vid).known() {
Some(u) => {
self.relate(&u, &u)
}
None => Ok(c),
}
}
_ => {
relate::super_relate_consts(self, c, c)
}
}
}
}
pub trait RelateResultCompare<'tcx, T> {

View File

@ -1,12 +1,13 @@
use super::combine::{CombineFields, RelationDir};
use super::{Subtype};
use super::combine::{CombineFields, RelationDir, const_unification_error};
use super::Subtype;
use crate::hir::def_id::DefId;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::TyVar;
use crate::ty::subst::SubstsRef;
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::mir::interpret::ConstValue;
/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@ -100,6 +101,47 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a);
let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b);
let a_is_expected = self.a_is_expected();
if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
match (a_eval.val, b_eval.val) {
(ConstValue::Infer(InferConst::Var(a_vid)),
ConstValue::Infer(InferConst::Var(b_vid))) => {
infcx.const_unification_table
.borrow_mut()
.unify_var_var(a_vid, b_vid)
.map_err(|e| const_unification_error(a_is_expected, e))?;
return Ok(a);
}
(ConstValue::Infer(InferConst::Var(a_id)), _) => {
self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
return Ok(a);
}
(_, ConstValue::Infer(InferConst::Var(b_id))) => {
self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
return Ok(a);
}
_ => {}
}
}
self.fields.infcx.super_combine_consts(self, a, b)?;
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b))
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b))
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -27,7 +27,7 @@ use crate::ty::error::TypeError;
use crate::ty::fold::{TypeFoldable, TypeVisitor};
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::ty::subst::Kind;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use rustc_data_structures::fx::FxHashMap;
use std::fmt::Debug;
@ -537,10 +537,10 @@ where
}
fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
let a = self.infcx.shallow_resolve(a);
let a = self.infcx.shallow_resolve_type(a);
if !D::forbid_inference_vars() {
b = self.infcx.shallow_resolve(b);
b = self.infcx.shallow_resolve_type(b);
}
match (&a.sty, &b.sty) {
@ -608,6 +608,24 @@ where
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(_, _)),
..
}) = a {
// FIXME(const_generics): I'm unsure how this branch should actually be handled,
// so this is probably not correct.
self.infcx.super_combine_consts(self, a, b)
} else {
debug!("consts(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance);
relate::super_relate_consts(self, a, b)
}
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
@ -853,7 +871,7 @@ where
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
use crate::infer::type_variable::TypeVariableValue;
debug!("TypeGeneralizer::tys(a={:?})", a,);
debug!("TypeGeneralizer::tys(a={:?})", a);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
@ -934,7 +952,7 @@ where
a: ty::Region<'tcx>,
_: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a,);
debug!("TypeGeneralizer::regions(a={:?})", a);
if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
@ -963,6 +981,26 @@ where
Ok(replacement_region_vid)
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
_: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("TypeGeneralizer::consts(a={:?})", a);
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(_, _)),
..
}) = a {
bug!(
"unexpected inference variable encountered in NLL generalization: {:?}",
a
);
} else {
relate::super_relate_consts(self, a, a)
}
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
@ -971,7 +1009,7 @@ where
where
T: Relate<'tcx>,
{
debug!("TypeGeneralizer::binders(a={:?})", a,);
debug!("TypeGeneralizer::binders(a={:?})", a);
self.first_free_index.shift_in(1);
let result = self.relate(a.skip_binder(), a.skip_binder())?;

View File

@ -1,11 +1,12 @@
use super::SubregionOrigin;
use super::combine::{CombineFields, RelationDir};
use super::combine::{CombineFields, RelationDir, const_unification_error};
use crate::traits::Obligation;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::TyVar;
use crate::ty::fold::TypeFoldable;
use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use crate::mir::interpret::ConstValue;
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@ -133,6 +134,50 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a);
let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b);
// Consts can only be equal or unequal to each other: there's no subtyping
// relation, so we're just going to perform equating here instead.
let a_is_expected = self.a_is_expected();
if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
match (a_eval.val, b_eval.val) {
(ConstValue::Infer(InferConst::Var(a_vid)),
ConstValue::Infer(InferConst::Var(b_vid))) => {
infcx.const_unification_table
.borrow_mut()
.unify_var_var(a_vid, b_vid)
.map_err(|e| const_unification_error(a_is_expected, e))?;
return Ok(a);
}
(ConstValue::Infer(InferConst::Var(a_id)), _) => {
self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
return Ok(a);
}
(_, ConstValue::Infer(InferConst::Var(b_id))) => {
self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
return Ok(a);
}
_ => {}
}
}
self.fields.infcx.super_combine_consts(self, a, b)?;
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -1,6 +1,7 @@
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::error::TypeError;
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::error::{TypeError, ConstError};
use crate::ty::relate::{self, Relate, TypeRelation, RelateResult};
use crate::mir::interpret::ConstValue;
/// A type "A" *matches* "B" if the fresh types in B could be
/// substituted with values so as to make it equal to A. Matching is
@ -78,6 +79,35 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> {
}
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
match (a_eval.val, b_eval.val) {
(_, ConstValue::Infer(InferConst::Fresh(_))) => {
return Ok(a);
}
(ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
return Err(TypeError::ConstError(
ConstError::Mismatch(relate::expected_found(self, &a, &b))
));
}
_ => {}
}
}
relate::super_relate_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -16,9 +16,10 @@ use rustc::traits::{
Environment,
InEnvironment,
};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt, InferConst};
use rustc::ty::subst::Kind;
use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc::mir::interpret::ConstValue;
use syntax_pos::DUMMY_SP;
use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst};
@ -203,7 +204,7 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> {
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
let b = self.infcx.shallow_resolve(b);
let b = self.infcx.shallow_resolve_type(b);
debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b);
if let &ty::Bound(debruijn, bound_ty) = &a.sty {
@ -275,4 +276,44 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> {
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::LazyConst<'tcx>,
b: &'tcx ty::LazyConst<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
..
}) = a {
if *debruijn == self.binder_index {
self.unify_free_answer_var(*bound_ct, b.into())?;
return Ok(b);
}
}
match (a, b) {
(
ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)),
..
}),
ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)),
..
}),
) => {
assert_eq!(a_debruijn, b_debruijn);
assert_eq!(a_bound, b_bound);
Ok(a)
}
// Everything else should just be a perfect match as well,
// and we forbid inference variables.
_ => match ty::relate::super_relate_consts(self, a, b) {
Ok(ct) => Ok(ct),
Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err),
}
}
}
}